PowerShell

Azure AD – PowerShell Script to Change UPN of All Users in a Group

Posted on Updated on

Imagine that if users in a domain have a UPN suffix which is not a public domain, such as @company.local instead of @company.com.  When those users synchronize into Azure AD for EMS, Intune, O365, etc., then the users’ UPNs will be @company.onmicrosoft.com instead of a friendly @company.com UPN for logging into portals or for enrolling devices.

This is an instance that recently occurred for a customer.  There are plenty of PowerShell examples around for how to change the UPN of users in Azure AD.  However, this customer wanted the ability to only change the users that were part of a specific AD group, rather than the entire organization.

The following PowerShell script can do exactly just that.  But please use extreme caution and thoroughly test the script first as well as the impact to those users and the Microsoft cloud technologies which they use.  There are high risks and many possible negative side effects.  Use this script at your own risk.


# This script will change the UPN for the user members of an AD group
$AdGrp = "EMS_Users"
$oldSuffix = "@company.onmicrosoft.com"
$newSuffix = "@company.com"

# Get the AD Group in Azure
$AzAdGrp = Get-MsolGroup -All | Where-Object { $_.DisplayName -eq $AdGrp }
$AzAdGrp_members = Get-MsolGroupMember -All -GroupObjectId $AzAdGrp.ObjectId
write-host "Total members of group: " $AzAdGrp_members.Count

# Create array of users to change
# Example command to test only a portion of the users in the group:
$users = Get-MsolGroupMember -All -GroupObjectId $AzAdGrp.ObjectId | Get-MsolUser | Where-Object { $_.UserPrincipalName -like "*john.doe*"}
# Command to run for all users in the group:
# $users = Get-MsolGroupMember -All -GroupObjectId $AzAdGrp.ObjectId | Get-MsolUser

# Change UPN of users
$users | ForEach-Object {
    $newUpn = $_.UserPrincipalName.Replace($oldSuffix,$newSuffix)
    Set-MsolUserPrincipalName -NewUserPrincipalName $newUpn -UserPrincipalName $_.UserPrincipalName
    Write-host "New UPN assigned: " $newUpn
}

 

Advertisements

App-V 5.0 bulk add and publish applications

Posted on Updated on

Piggybacking on Aaron Parker’s blog post for App-V 5 PowerShell One Liners – Adding and Publishing App-V Server Packages, I’ve extended the usage of the script to parse all sub-directories of a folder to add/publish any .appv package.

$grpName = "lab\Domain Users"
$appContentShare = "\\appv5-server\content-share"
# Get the list of AppV files
Set-Location $appContentShare
$filesList = get-childitem $_.DirectoryName -include *.appv -recurse

# Bulk import/publish/grant access
ForEach ($file in $filesList) {
   Import-AppvServerPackage -PackagePath $filesList | Publish-AppvServerPackage -Verbose | Grant-AppvServerPackage -Groups $grpName -Verbose
}

And that’s all it takes!

ConfigMgr migration script – Driver source path conversion

Posted on Updated on

Use the following PowerShell script to convert driver files’ source path from an old server location to the new location.

Updated 5/5/14: fixed creation of $ChangePath variable to account for mixed-case of the $OldPath and $NewPath.

# By https://t3chn1ck.wordpress.com
# Version 1.1

# Site Code + :
Set-Location "GAL:"

# Note: max query limit is 1000 items, need to increase value as appropriate
Set-CMQueryResultMaximum 2000

$DriverArray = Get-CMDriver
$OldPath = "\\2007SERVER\source$"
$NewPath = "\\2012SERVER\cmsource$"

ForEach ($Driver in $DriverArray){
   $OldPkgPath = $Driver.ContentSourcePath.ToLower()

   If ($OldPkgPath.StartsWith($OldPath)){
      $ChangePath = $OldPkgPath.Replace($OldPath.ToLower(), $NewPath.ToUpper())

      Set-CMDriver -Id $Driver.CI_ID -DriverSource $ChangePath
      Write-Host "Changed: " $Driver.CI_ID " to " $ChangePath -f Green
   } Else {
      Write-Host "Not changed: " $Driver.CI_ID " of " $OldPkgPath -f DarkYellow
   }
}

ConfigMgr migration script – Disable non-limited OS of Package/Programs

Posted on Updated on

Let’s say you’ve just migrated hundreds of ConfigMgr packages where the Program(s) of those packages were not previously limited. Meaning that they were set to be able to run on any and every system … including servers. That could potentially cause a HUGE outage with significant consequences in the case of an administrative goof.  Ideally in this situation, you would want/need to limit those package to the proper OS (such as All Win7 x64).

Unfortunately there are no PowerShell cmdlets that can set the OS limiting of a Program/Package.  So as a safety precaution the below PowerShell script can be used to disable any Program of migrated Packages if the Program was not limited.  In this way it can give an admin the opportunity to manually remediate the Program configuration before an accident occurs!

# By https://t3chn1ck.wordpress.com

# Site Code + :
$SiteCode = "GAL"
Set-Location $SiteCode":"

clear
$ProgramArray = Get-CMProgram

ForEach ($Program in $ProgramArray){
    $OSCount = $Program.SupportedOperatingSystems.Count

    If ($OSCount.Equals(0)){
        $Program.ProgramFlags.ToString()

        if ($Program.PackageID.StartsWith($SiteCode)){
            # Do nothing
            Write-Host "Skipping non-migrated package " $Program.PackageName -ForegroundColor DarkYellow

        } ElseIf (($Program.ProgramFlags -band 0x00001000)) {
            # Program already disabled
            # Bitwise ProgramFlags operator found at http://msdn.microsoft.com/en-us/library/hh949572.aspx
            Write-Host "Skipping disabled program " $Program.PackageName -ForegroundColor DarkYellow

        } Else {
            Write-Host "No OS limits on active package " $Program.PackageName  -ForegroundColor Red
            #Disable-CMProgram -PackageId $Program.PackageID -ProgramName $Program.ProgramName
            Write-Host "Disabled Program: " $Program.ProgramName
        }

    } Else {
        Write-Host $OSCount " OS limits set for " $Program.PackageName " : " $Program.ProgramName -ForegroundColor DarkGreen
    }

    Write-Host "============="
}

ConfigMgr migration script – Change limiting collections

Posted on Updated on

When doing a migration of ConfigMgr, it could be handy to bulk convert collections that were migrated and need a new limiting collection. The below code example checks the last modified date of the collection … and if it was changed “today” (date when the script executes), then it will set the collection to have a new limiting collection. In this example, it was setting the limiting collection to one that I had created for All Windows Workstation Clients.

# https://t3chn1ck.wordpress.com

# Site code of primary (e.g. GAL:)
Set-Location "GAL:"

# Increase the max number of collection as follows
Set-CMQueryResultMaximum 300

# Collection ID of the new limiting collection
$LimitingCollection = "GAL00003"

# Build array of all collections
$CollArray = Get-CMDeviceCollection

# Get today's date to convert collections created TODAY
# If needing to do date other than TODAY, then set static string value as MM/DD/YYYY
$Today = get-date -format d
Write-Host "Today's date: " $Today

ForEach ($Collection in $CollArray){
# Get collection ID and creation date
$CollID = $collection.CollectionID
$CollDate = $Collection.LastChangeTime.Date.ToShortDateString()

If ($CollID.StartsWith("SMS")) {
# No need to convert "out of box" collections
Write-Host "Skipped SMS Pkg ID: " $CollID -f DarkYellow
} Else {
If ($CollDate.Equals($Today)) {
If ($Collection.LimitToCollectionID.Equals($LimitingCollection)) {
# Already converted if limiting collection already matches
Write-Host "Limiting collection already set for: " $Collection.Name

} Else {
# Date match of collection with today to be converted
Set-CMDeviceCollection -CollectionId $Collection.CollectionID -LimitingCollectionId $LimitingCollection
Write-Host "Set new limiting collection for: " $Collection.Name -ForegroundColor Green
}
} Else {
# Dates that do not match today should not be converted
Write-Host "Mismatch date: " $CollDate " for " $Collection.Name -f DarkRed
}
}
}

Fixes to Microsoft Package Source Conversion Scripts

Posted on Updated on

The Microsoft PFE team blog (ConfigMgr Dogs) has a very good sample scripts  for converting Package source files to a new location.  Located from http://blogs.technet.com/b/configmgrdogs/archive/2013/05/09/package-amp-application-source-modification-scripts.aspx

However, I have found a couple of logical bugs.  The first is that when using the command “Set-CMPackage -Name $Package.Name -Path $ChangePath”, this will cause ALL packages with the same name to be converted over to the same value as listed by $ChangePath .  Instead of using parameter “-Name $Package.Name”, this code needs to use “-Id $Package.PackageID”.

There second and confirmed logical bug if that is caused by the package path being case sensitive such that the conversion of $OldPath to $NewPath fails (no errors generated).

Finally, as an enhancement, it would be good for packages that have already been converted to not be run again.

Below is my rendition of the script


# Original script from
# http://blogs.technet.com/b/configmgrdogs/archive/2013/05/09/package-amp-application-source-modification-scripts.aspx
# Modifications by https://t3chn1ck.wordpress.com

Write-Host "#######################################################################"
Write-Host "##        Matts ConfigMgr 2012 SP1 Package Source Modifier           ##"
Write-Host "##                blogs.technet.com/b/ConfigMgrDogs                  ##"
Write-Host "#######################################################################"

# Site Code + :
Set-Location "S01:"

$PackageArray = Get-CMPackage
$OldPath = "\\2007SERVER\source$"
$NewPath = "\\2012SERVER\cmsource$"

ForEach ($Package in $PackageArray){
   $OldPkgPath = $Package.PkgSourcePath.ToLower()

   If ($OldPkgPath.StartsWith("\\2007server")){
      $ChangePath = $Package.PkgSourcePath.ToLower()
      $ChangePath = $ChangePath.Replace($OldPath, $NewPath)

      Set-CMPackage -Id $Package.PackageID -Path $ChangePath
      Write-Host "Changed: " $Package.Name " to " $ChangePath -f Green
   } Else {
      Write-Host "Not changed: " $Package.Name -f DarkYellow
   }
}

App-V 5.0 Demo – User scripting / StartProcess

Posted on Updated on

This is the walk-through for demo #3 from my Microsoft Master webcast on App-V 5.0 scripting.  For the full webcast information, visit https://t3chn1ck.wordpress.com/2014/02/03/playback-of-microsoft-master-app-v-5-0/.

This demo is on scripting for a process to run when a user launches the application.  I’m using the game of Sudoku (obtained from SourceForge) and when it is launched by the user, it opens a text file on the “rules” of the game.  For this example, I am using the standalone App-V infrastructure, not ConfigMgr 2012 R2.

  1. The package has already been sequenced.  It’s just a simple set of files (and the main .exe) that I copied into the Program Files directory.  After sequencing, I added the PowerShell script to perform the operation.appv-sudoku-demo01
  2. The PowerShell script will obtain it’s current working directory and then execute the text file specified.
    
    function Get-ScriptDirectory {
      $Invocation = (Get-Variable MyInvocation -Scope 1).Value
      Split-Path $Invocation.MyCommand.Path
    }
    
    $vfsPath = Join-Path (Get-ScriptDirectory) ""
    write-host $vfsPath
    
    Set-Location $vfsPath
    Invoke-Item "Sudoku Rules.txt"
    
  3. In the UserConfig.xml we define that whenever Sudoku.exe is launched, then App-V will execute powershell.exe with the command line to run our .ps1 script.
    <UserScripts>
    <StartProcess RunInVirtualEnvironment="false">
    <Path>powershell.exe</Path>
    <Arguments>-ExecutionPolicy Bypass -File "[{AppVPackageRoot}]\..\Scripts\OpenRules.ps1"</Arguments>
    <Wait RollbackOnError="true"/>
    <ApplicationId>[{AppVPackageRoot}]\Sudoku.exe</ApplicationId>
    </StartProcess>
    </UserScripts>
    
  4. Now add the package into the App-V console and assign to a user group as per standard process.  Then follow my guideline on how to activate the custom UserConfig scripts.  Finally, with the test user, update the App-V client so that Sudoku becomes available.

Once Sudoku is launched, the PowerShell script will very quickly execute (so fast that I cannot capture a screen shot).  But we will have the text file open with rules for learning how to play the game!

appv-sudoku-demo02

Furthermore, the App-V operational events show execution of the script.

appv-sudoku-demo03