Wednesday, January 18, 2017

Miracast Connections Drop Out Constantly

Recently, during a projector upgrade project, we decided to try and make things a little bit easier on the end users and provide nice HD TVs and Miracast technology so they could connect without having to fuss with VGA and HDMI cables. (It gave us a great reason to push upgrades to Windows 10, too!)

We went with decent TV makes and the Microsoft Wireless Display Adapter v2 for the Miracast dongle. (Only to find out that all of the TVs we purchased actually have a builtin Miracast function, but we stuck with the Microsoft brand as the "official" connection point.)

This project went very well for some time, but then we began having these connections drop out constantly. It got to the point that we  truly regretted ever having purchased the TVs in  the first place. But, as things stood, he we were, with great looking TVs, but not viable way of connecting and, more importantly, staying connected.

At first, we thought that it possibly could be something with one of the 2.4GHz channels that the Miracast was talking on was simply overloaded. We decided to actually go ahead and purchase a metageek Wi-Spy DBx and Chanalyzer license to help us try and figure this out. [Not sponsored by metageek for this at all - it's just the tool we went with.]

At first, we were seeing the DIRECT-* SSIDs that are created during an active Miracast session running on Channel 6 of the 2.4GHz spectrum. Sadly, this was along with what appeared to be most of  the other APs in our office. We decided to take our APs, and completely disable Channel 6 on the 2.4GHz radio.

[TIP: If you're trying to diagnose this issue, in our experience, you can not view a DIRECT-* connection in Chanalyzer, if that same computer is the one hosting the Miracast connection. 2 PCs required, folks.]

The problem persisted.

Well, let's check and make sure that the Miracast was still trying to connect on Channel 6. Granted this is the next day, but here we are, sitting on Channel 11. We still seemed to have a bunch  of interference and overlap on all of our SSIDs. We turned our Tx limits lower. We started with Tx minimum  level of 10 and a maximum of 17. All of our APs were transmitting on Tx 10, and still interfering with each other. We changed this to Tx minimum 5, Tx maximum 10. All of the APs immediately dropped to Tx 5. We still had some interference, but the dB levels were much more acceptable.

The Miracast issue persisted.

We disabled the 2.4GHz band entirely.

This seemed to work out quite well, but is really not a viable solution in the long term. We re-enabled the 2.4GHz band and decided to leave it be and see if we could capture anything funky going on with Chanalyzer.

It turns out, every 30 minutes, with an active Miracast session going on, you could put money on the connection dropping. However, we didn't see anything too horribly awry on Chanalyzer. Let's dig into the FortiGate logs.


Tuesday, January 10, 2017

Backing up Amazon Route 53 DNS Entries with PowerShell

While AWS is very solid, it's nice  to be able to have a backup of your DNS  zones in Route 53, especially if  you're getting ready to make some major changes. Despite looking, I wasn't able to find anything out there that automated this.

The only required changes on your part would be to populate the $AccessKey, $SecretKey, and Email information (If you  plan on shipping the output into mail). Or, you can simply put this information in at run time.

#requires -Version 3.0 -Modules AWSPowerShell, PSCX
Function Backup-AWSRoute53 
{
  param(
    [switch]
    $sendEmail,
    [string]
    $AccessKey = '',
    [string]
    $SecretKey = '',
    [string]
    $EmailSender = 'Mike@Riston.Me',
    [string]
    $EmailRecipient = 'Mike@Riston.Me',
    [string]
    $SMTPServer = 'mail-server@riston.me'
  )

  
  #Prep
  Import-Module -Name AWSPowerShell
  Set-AWSCredentials -AccessKey $AccessKey -SecretKey $SecretKey -StoreAs default
  Initialize-AWSDefaults -ProfileName default -Region us-east-1

  #File System Prep
  $StorageFolder = New-Item -Path "C:\scripts\PowerShell\AWS_Route53\$(Get-Date -Format yyyy.MMM.dd-hhtt)" -ItemType Directory 
  $StorageFolder = Get-Item -Path "C:\scripts\PowerShell\AWS_Route53\$(Get-Date -Format yyyy.MMM.dd-hhtt)"

  #Find All R53 Hosted Zones
  $Zones = Get-R53HostedZones

  foreach ($zone in $Zones) 
  {
    #Create Zone File
    $OutFile = New-Item -Path "$($StorageFolder.FullName)\$($zone.Name).csv" -ItemType File
  
    foreach ($Recordset in (Get-R53ResourceRecordSet -HostedZoneId $zone.Id).ResourceRecordSets) 
    {
      if ($Recordset.ResourceRecords.Count -gt 1) 
      {
        $data = ''
        foreach ($entry in $Recordset.ResourceRecords) 
        {
          $data = $data + $($entry.value) + ','
        }
      }
      ELSE 
      {
        $data = ''
        $data = $Recordset.ResourceRecords.Value
      }

      #Generate Custom Object
      #REF:https://technet.microsoft.com/en-us/library/hh750381.aspx
      $ReturnArray = New-Object -TypeName PSObject -Property (@{
          'Zone'                  = $zone.Name
          'CallerReference'       = $zone.CallerReference
          'Name'                  = $Recordset.Name
          'Type'                  = $Recordset.Type
          'SetIdentifier'         = $Recordset.SetIdentifier
          'Weight'                = $Recordset.Weight
          'Region'                = $Recordset.Region
          'GeoLocation'           = $Recordset.GeoLocation
          'TTL'                   = $Recordset.TTL
          'ResourceRecord'        = $data
          'AliasTarget'           = $Recordset.AliasTarget
          'TrafficPolicyInstanceID' = $Recordset.TrafficPolicyInstanceId
      })
    
      $ReturnArray | Export-Csv $OutFile -Append
    }
  }

  Get-Item -Path $StorageFolder.FullName | Write-Zip -Level 9 -OutputPath "C:\scripts\PowerShell\AWS_Route53\$($StorageFolder.BaseName).zip" -ErrorAction SilentlyContinue
  $OutputZip = Get-Item -Path "C:\scripts\PowerShell\AWS_Route53\$($StorageFolder.BaseName).zip"
  Get-ChildItem $StorageFolder -Recurse | Write-Zip -Level 9 -OutputPath "C:\scripts\PowerShell\AWS_Route53\$($StorageFolder.BaseName).zip" -Append
  Remove-Item $StorageFolder -Recurse

  if ($sendEmail) 
  {
    Send-MailMessage -SmtpServer $SMTPServer -To $EmailRecipient  -From $EmailSender -Subject 'AWS Route53 Backup' -Attachments  $OutputZip
  }
}

Until Next Time!
Mike

Wednesday, August 31, 2016

Backup-ExchangeWhiteLists

We've been working a lot recently at work on the whitelists for Exchange Online. It'd be nice to have a script to back up all of those whitelists/blacklists for future reference.

The following requires you have a Connect-ExchangeOnline function, as well as PSCX installed (For write-zip)

You can throw a -SendEmail flag, which will use Send-MailMessage to send a mail with the created ZIP file to the defined addresses.

Function Backup-ExchangeWhiteLists {
    param(
        [Switch]
            $SendEmail
        )

    #region Varialbes
        $BackupPath = "C:\scripts\powershell\EOL_WhitelistBackups\"
            New-Item $BackupPath -ItemType Directory -ErrorAction SilentlyContinue -Force
        [String]$Runtime = Get-Date -Format yyyy.MM.dd_HH.mm.sstt
        $BackupZip = $BackupPath + $Runtime + ".zip"
        $StartingLocation = Get-Location

        $EmailRecipient = 'Automation@riston.me'
        $EmailSenders   = 'Automation@riston.me'
        $SMTPServer     = 'mysmtpserver.riston.local'
    #endregion


    $ConnectionState = (Get-PSSession | ? {$_.ConfigurationName -eq "Microsoft.Exchange" -and $_.State -eq "Opened" -and $_.ComputerName -eq "ps.outlook.com"}).count
        if ($ConnectionState -eq 0) {
            #return "Disconnected"
            Connect-ExchangeOnline
            }

    
    $AllPolicies = Get-HostedContentFilterPolicy

    foreach ($SpamPolicy in $AllPolicies) {
        
        $OutFile = $BackupPath + $Runtime + "_" + $SpamPolicy.Name + "_AllowedSenderDomains.csv"
        $SpamPolicy.AllowedSenderDomains | Export-Csv -Path $OutFile -NoTypeInformation

        $OutFile = $BackupPath + $Runtime + "_" + $SpamPolicy.Name + "_AllowedSenders.csv"
        $SpamPolicy.AllowedSenders | Export-Csv -Path $OutFile -NoTypeInformation

        $OutFile = $BackupPath + $Runtime + "_" + $SpamPolicy.Name + "_BlockedSenderDomains.csv"
        $SpamPolicy.BlockedSenderDomains | Export-Csv -Path $OutFile -NoTypeInformation

        $OutFile = $BackupPath + $Runtime + "_" + $SpamPolicy.Name + "_BlockedSenders.csv"
        $SpamPolicy.BlockedSenders | Export-Csv -Path $OutFile -NoTypeInformation

    }

    Set-Location $BackupPath

    $BackupFiles = Get-ChildItem $BackupPath*csv
    $BackupFiles | Write-Zip -Level 9 -OutputPath $BackupZip
    $BackupFiles | Remove-Item -Force -ErrorAction SilentlyContinue

    Set-Location $StartingLocation


    if ($SendEmail) {
        Send-MailMessage -SmtpServer $SMTPServer -To $EmailRecipient -From $EmailSenders -Subject "Exchange Spam Filter Backups - $($Runtime)" -Attachments $BackupZip
        }

}

This results in a folder of .ZIP files with contents of all of the [Allowed\Denied] [Senders\Sender Domains] for your backups.



Until Next Time!
Mike

Wednesday, June 1, 2016

Backing up all SCSM Management Packs

As with most things I tend to post, they may not be the most complex things in the world, but they are things that are in my routine.

The following is a simple script to export and back up all of the Management Packs in my Service Manager installation. Most of the code is a rip/replace from my On Demand Backup of All Registered DHCP Servers.

Import-Module smlets
Import-Module pscx 

#region User Changable Variables
$OutputFolderBase = 'C:\working\SCSM_MPBackups\'
$SCSM_ManagementServer = 'ServiceManager.riston.me'
$HistoricalCopiesToKeep = 50
#endregion

#region General Variables & Output Object Locations
$now = Get-Date -DisplayHint DateTime -Format yyyy_MMM_dd-HH-mm-ss-tt
[String]$OutputFolder = "$OutputFolderBase$now\"
Write-Host -BackgroundColor Black -ForegroundColor Green $OutputFolder
$OutputFolder = New-Item -Path $OutputFolder -ItemType Directory
#endregion

#region Backup All SM MPs
    Get-SCSMManagementPack -ComputerName $SCSM_ManagementServer | Export-SCSMManagementPack -TargetDirectory $OutputFolder
#endregion

#region Clean Up

#Write out our zip file using the Write-Zip cmdlet provided from PSCX
Write-Zip -Path $OutputFolder -Level 9 -IncludeEmptyDirectories $OutputFolderBase\$now.zip

#Remove the uncompressed source files locally
Remove-Item $OutputFolder -Force -Recurse

#endregion

#region Trim Historical Copies To Keep
    #Find number already saved
    $numbersaved = Get-ChildItem -Path $OutputFolderBase *zip
    #Store number of zip files to delete 
    $numbertotrim = $numbersaved.count - $HistoricalCopiesToKeep

    #Confirm number to delet is not 0 or lt 0
    if ($numbertotrim -le 0) {
        #Do Nothing.
        #No extra copies Exist.
        Write-Host Not deleting any copies. Current ZIP files saved is $numbersaved.Count
        } ELSE {
            #We have a valid $numbertotrim. Time to delete (if needed)
                Write-Host We may have extra copies. We are going to delete the following.
                $ZIPsToDelete = Get-ChildItem -Path $OutputFolderBase *zip | sort LastWriteTime | select -First $numbertotrim
                $ZIPsToDelete
                $ZIPsToDelete | Remove-Item -Force -ErrorAction SilentlyContinue -Verbose
                }

#endregion

One quick note about this one - the PSCX compression take me down to about 5-6Mb in size. As this is significantly larger than the previous DHCP backup posting, it may be worth while to filter out your target management packs. To do this, follow the example below. Hopefully you've historically done something that is 'standard' in your custom management packs that you can easily filter on. For instance, I've always put "Riston" somewhere in my management pack descriptions.

$ManagementPacks = Get-SCSMManagementPack -ComputerName $SCSM_ManagementServer;
$ManagementPacks | ? {$_.Description -like "*Riston*"} | Export-SCSMManagementPack -TargetDirectory $OutputFolder


Until Next Time!
Mike

Thursday, May 5, 2016

What's In Your Profile #5 - Add-SendAsPermission

Adding SendAs permissions for a mailbox on Exchange Online tends to be one of the pickier things we tend to need to do. Canonical issues reach the top of the list of common issues, causing the GUI interface to Exchange Online to become worthless. Adding the permission with PowerShell has been my go to.

Typically in the past, I've needed to use the Add-ADPermission cmdlet to get this function, but now that we're mostly migrated to Exchange Online, I've started using Add-RecipientPermission more frequently. You can find examples of both below. The Add-RecipientPermission is written as a function as it's something I've added into my $profiile.


function Add-SendAsPermission {
     param
     (
           [Parameter(Mandatory = $True)]
           [String]$User = (Read-Host Who Needs Permissions?)
           ,
           
           [Parameter(Mandatory = $True)]
           [String]$SharedMailbox = (Read-Host Where do they need permissons? `(Enter Full Email`))
    )
    $useraccount = Get-ADUser $User -Properties EmailAddress
    $useraccountemail = $useraccount.EmailAddress
    write-host $useraccount
    Write-Host $useraccountemail

    Add-RecipientPermission -Identity $SharedMailbox -Trustee ($useraccount.EmailAddress) -AccessRights SendAs -Verbose
    }

And a quick example of Add-ADPermission
Add-ADPermission SharedMailbox@riston.me -User mriston -AccessRights ExtendedRight -ExtendedRights "SendAs" -Verbose;

Until Next Time!
Mike

Wednesday, May 4, 2016

WQL Query Store - Installed Products

This is going to be a 'live' document that I'll store WQL queries to be used in wbemtest or ConfigMgr custom detection rules for various bits of installed software. If you have any you'd like to contribute, please comment and help out!



  • Visio Professional * - Click To Run
    • select * from win32_installedwin32program WHERE Name LIKE 'Microsoft Visio Professional % - en-us'
  • Visio Professional 2013 - Click To Run
    • select * from win32_installedwin32program WHERE Name = 'Microsoft Visio Professional 2013 - en-us'
  • Visio Professional 2016 - Click To Run
    • select * from win32_installedwin32program WHERE Name = 'Microsoft Visio Professional 2016 - en-us'



Friday, April 22, 2016

Dynamically Creating PKGX Files for All Components in a Task Sequence

Sometimes, when a larger overhaul of a task sequence is done, you're left with manually creating PKGX files for your remote distribution sites.

I started digging into a way to dynamically create these by just supplying the PackageIDs for the various applications/boot images one at a time.

As these things turn out, Kristoffer Henriksson over at sysadmins.no has already done me one better.
Kristoffer's script is great. Simply supply your SCCM server, the DP that already contains the distributed content, and get a cup of coffee.

<
.SYNOPSIS
 Exports all references in a task sequence as .pkgx files

.DESCRIPTION
 Exports all Packages, Applications, OS Images, Bootimages and Driverpackages referenced by a Task Sequence as .pkgx files to desired location.
 Specify the -ContentDistribution parameter as $True to start contentdistribution as well (Also requires the -DestionationDP parameter).
 Use FQDN server names.

.EXAMPLE
 .\Export-TSPrestageFiles.ps1 -CMServer Server1.domain.local -SiteCode 123 -SourceDP DP1.domain.local -TSID 1230001

.NOTES
 Created by Kristoffer Henriksson
>


[CmdletBinding()]
param(
    [Parameter(Mandatory=$True,Helpmessage="Please Enter Site Server Name")]
    [String]$CMServer,

    [Parameter(Mandatory=$True,Helpmessage="Please Enter Sitecode")]
    [String]$SiteCode,

    [Parameter(Mandatory=$True,Helpmessage="Please Enter Source DP")]
    [String]$SourceDP,

    [Parameter(Mandatory=$True,Helpmessage="Please Enter Task Sequence ID")]
    [String]$TSID,

    [Parameter(Mandatory=$False)]
    [String]$Filepath = "$env:USERPROFILE\Documents",

    [Parameter(Mandatory=$False)]
    $ContentDistribution = $False,

    [Parameter(Mandatory=$False)]
    $DestinationDP
    )

Import-Module -Name "${env:ProgramFiles(x86)}\Microsoft Configuration Manager\AdminConsole\bin\ConfigurationManager.psd1"
CD $SiteCode":"

$SMS_WMI = "root\SMS\site"
$WMINameSpace = $SMS_WMI + "_" + $SiteCode

Write-Host "Retrieving Task Sequence References from WMI..."
$Packages = Get-WmiObject -ComputerName $CMServer -Namespace $WMINameSpace -Class SMS_TaskSequencePackageReference | Where-Object -Filterscript {$_.PackageID -eq $TSID} | Where-Object -FilterScript {$_.ObjectType -eq "0"}
$DriverPackages = Get-WmiObject -ComputerName $CMServer -Namespace $WMINameSpace -Class SMS_TaskSequencePackageReference | Where-Object -Filterscript {$_.PackageID -eq $TSID} | Where-Object -FilterScript {$_.ObjectType -eq "3"}
$OSImages = Get-WmiObject -ComputerName $CMServer -Namespace $WMINameSpace -Class SMS_TaskSequencePackageReference | Where-Object -Filterscript {$_.PackageID -eq $TSID} | Where-Object -FilterScript {$_.ObjectType -eq "257"}
$BootImages = Get-WmiObject -ComputerName $CMServer -Namespace $WMINameSpace -Class SMS_TaskSequencePackageReference | Where-Object -Filterscript {$_.PackageID -eq $TSID} | Where-Object -FilterScript {$_.ObjectType -eq "258"}
$Applications = Get-WmiObject -ComputerName $CMServer -Namespace $WMINameSpace -Class SMS_TaskSequencePackageReference | Where-Object -Filterscript {$_.PackageID -eq $TSID} | Where-Object -FilterScript {$_.ObjectType -eq "512"}

Write-Host "Exporting Packages..."
Foreach ($Object in $Packages){
    $FileName = $Filepath + "\" + $Object.ObjectID + ".pkgx"
        Publish-CMPrestageContent -DistributionPointName $SourceDP -FileName $FileName -PackageId $Object.ObjectID
        if($ContentDistribution -eq $True){
            Start-CMContentDistribution -PackageId $Object.ObjectID -DistributionPointName $DestinationDP
            }
        Write-Host $Object.ObjectName" Exported to" $Filepath
    }
Write-Host "Packages Exported"

Write-Host "Exporting Driverpackages..."
Foreach ($Object in $DriverPackages){
    $FileName = $Filepath + "\" + $Object.ObjectID + ".pkgx" 
        Publish-CMPrestageContent -DistributionPointName $SourceDP -DriverPackageId $Object.ObjectID -FileName $FileName 
        if($ContentDistribution -eq $True){
            Start-CMContentDistribution -DriverPackageId $Object.ObjectID -DistributionPointName $DestinationDP
            }
        Write-Host $Object.ObjectName" Exported to" $Filepath
    }
Write-Host "Driverpackages Exported"

Write-Host "Exporting OS Images..."
Foreach ($Object in $OSImages){
    $FileName = $Filepath + "\" + $Object.ObjectID + ".pkgx"
        Publish-CMPrestageContent -DistributionPointName $SourceDP -FileName $FileName -OperatingSystemImageId $Object.ObjectID
        if($ContentDistribution -eq $True){
            Start-CMContentDistribution -OperatingSystemImageId $Object.ObjectID -DistributionPointName $DestinationDP
            }
        Write-Host $Object.ObjectName" Exported to" $Filepath
    }
Write-Host "OS Images Exported"

Write-Host "Exporting Bootimage..."
Foreach ($Object in $BootImages){
    $FileName = $Filepath + "\" + $Object.ObjectID + ".pkgx"
        Publish-CMPrestageContent -BootImageId $Object.ObjectID -DistributionPointName $SourceDP -FileName $FileName
        if($ContentDistribution -eq $True){
            Start-CMContentDistribution -BootImageId $Object.ObjectID -DistributionPointName $DestinationDP
            }
        Write-Host $Object.ObjectName" Exported to" $Filepath
    }
Write-Host "Bootimage Exported"

Write-Host "Exporting Applications..."
Foreach ($Object in $Applications){
    $FileName = $Filepath + "\" + $Object.RefPackageID + ".pkgx"
        Publish-CMPrestageContent -ApplicationName $Object.ObjectName -DistributionPointName $SourceDP -FileName $FileName
        if($ContentDistribution -eq $True){
            Start-CMContentDistribution -ApplicationName $Object.ObjectName -DistributionPointName $DestinationDP
            }
        Write-Host $Object.ObjectName" Exported to" $Filepath
    }
Write-Host "Applications Exported"

$TSName = (Get-CMTaskSequence -Id $TSID).Name
Write-Host "All References from $TSName Exported"

Monday, April 11, 2016

DISM - Adding a batch of drivers

Sometimes we get a new model of laptop that doesn't always play nicely with the existing WinPE drivers I already have injected into my boot image. I do it so infrequently that I always have to /? my way through DISM to get the proper DISM syntax to get the new drivers into my image.

Enough is enough! Time to make a .bat!


SET WIMPATH=C:\_working_\OEM_BOOT_IMAGE_x64.wim
SET MOUNTDIR=C:\_working_\mount
SET DRIVERPATH=C:\_working_\7710-WIN10-A02-PK00D\7710\win10\x64\network

mkdir %MOUNTDIR%


dism /mount-image /imagefile:%WIMPATH% /mountdir:%MOUNTDIR% /index:1

dism /Image:%MOUNTDIR% /Add-Driver /Driver:%DRIVERPATH% /Recurse /ForceUnsigned

dism /Unmount-Image /MountDir:%MOUNTDIR% /Commit

Hope it helps someone out there!

Thursday, April 7, 2016

What's In Your Profile - #4 - Get-GoogleLogo function

Sometimes I just need to confirm internet connectivity on a server. While it's simple enough to Test-Connection or any slew of other options, it's sometimes nice to switch it up and have a little more 'meat' to your confirmation.

Enter Get-GoogleLogo. Three guesses on what this one does!

Hope it helps someone out there!


function Get-GoogleLogo {
    $TesterImage = "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_150x54dp.png";
    $TesterImageDest = 'C:\users\Administrator\Desktop\GoogleTest.png';
    
    $webclient = New-Object System.Net.WebClient;
    
    try { 
        $webclient.DownloadFile($TesterImage, $TesterImageDest)
        }
    catch {
        Write-Warning "ERROR HAS OCCURRED"
        $ErrorDetect = $true;
        return "ERROR"
        }
    if (!$ErrorDetect) {
        Write-Host "File retrieved successfully";
        [String]$string = "Retrieved Google Logo Successfully at " + (Get-Date -DisplayHint DateTime)
        $string | Out-File $LogFile -Append -ea SilentlyContinue
        }
    
    
    Remove-Item $TesterImageDest -Force -ea SilentlyContinue;
    Remove-Variable -Name ErrorDetect -ea SilentlyContinue -Force
}

Monday, March 14, 2016

What's In Your Profile - #3 - Backup-Profile

Welcome back everyone! Time for another What's In Your Profile!

As we all know in IT, backups are key! I have this at the bottom of my profile to keep a current backup of my $profile on my OneDrive. However, I was thinking a while back, it sure would be nice to have a few copies of previous iterations. You know, just in case!

The following will allow for 100 (Feel free to change the numbers) backups of my $profile in my OneDrive. Once it reaches 100 (You'll see lots of red in your screen until you hit this point), it deletes the 100th and then copies the current version up.

Until next time! Hope this helps!

Function Backup-Profile {
    New-Item C:\users\mriston\OneDrive\PowerShell\__Profile\ `
  -ItemType Directory `
  -Force `
  -ErrorAction `
  SilentlyContinue ;
    $StorageLocation = "C:\users\mriston\OneDrive\PowerShell\__Profile\";
    
    $basename = (Get-Item $profile).baseName

    $files = (100..1);

    #Remove 100
    [String]$currentCopy = $basename + ".100";
    Remove-Item $StorageLocation\$currentCopy.ps1 -Force ;

    foreach ($file in $files) {
        
        if ($file -eq 100) {
   #Skip the 100 entry
   } ELSE {
    #Move the nth entry to the nth+1 file name
    #EX Backup 99 now becomes backup 100.
    #   Backup 98 now becomes backup 99.
    #   Backup 97 now becomes backup 98.
    
    # Store the 'destination' numbering
    $newitem = $file + 1
    
    # Move the current file to the destination number
    Move-Item "$StorageLocation\$basename.$file.ps1" `
     -Destination "$StorageLocation\$basename.$newitem.ps1"
            }
    }

 # Move the most recent backup to the .1 backup
    Move-Item $StorageLocation\$basename.ps1 $StorageLocation\$basename.1.ps1

 # Finally copy the current profile to the newest backup.
    Copy $profile $StorageLocation
}

# Now Run our actual backup
Backup-Profile