2

I'm moving the content source of pretty much everything in SCCM to a DFS share, and so I've got to change the source path for everything in the environment, and for the most part, I've got it coded out. There's some improvements I'd like to make, to clean up the code before I hit the big red button though.

For example, Powershell's .Replace method is case sensitive, and there are occasions where someone used uppercase in the server name in only PART of the name.

\\typNUMloc\ can be \\typNUMLOC\ or \\TYPNUMloc\ or \\TYPNUMLOC\. This makes for extra large If statements.

One of my functions is for the Drivers (not the Driver Packages, that I've tested with similar code, and I have only one mistyped path). Big Red Button commented out for safety.

$DriverArray = Get-CMDriver | Select CI_ID, ContentSourcePath | Where-Object {$_.ContentSourcePath -Like "\\oldNUMsrv\*"}
    Foreach ($Driver in $DriverArray) {
        $DriverID = $Driver.CI_ID
        $CurrPath = $Driver.ContentSourcePath

        # Checks and replaces the root path
        If ($CurrPath -split '\\' -ccontains 'path_dir') {
            $NewPath = $CurrPath.Replace("oldNUMsrv\path_dir","dfs\Path-Dir")
            #Set-CMDriver -Id $DriverID -DriverSource $NewPath
        } ElseIf ($CurrPath -split '\\' -ccontains 'Path_dir') {
            $NewPath = $CurrPath.Replace("oldNUMsrv\Path_dir","dfs\Path-Dir")
            #Set-CMDriver -Id $DriverID -DriverSource $NewPath
        } ElseIf ($CurrPath -split '\\' -ccontains 'Path_Dir') {
            $NewPath = $CurrPath.Replace("oldNUMsrv\Path_Dir","dfs\Path-Dir")
            #Set-CMDriver -Id $DriverID -DriverSource $NewPath
        } Else {
            Write-Host "Bad Path at $DriverID -- $CurrPath" -ForegroundColor Red
        }

        # Checks again for ones that didn't change propery (case issues)
        If ($NewPath -like "\\oldNUMsrv\*") {
            Write-Host "Bad Path at $DriverID -- $CurrPath" -ForegroundColor Red
        }
    }

But as you can tell, that's a lot of code that I shouldn't need to do. I know, I could use the -replace or -ireplace methods, but I end up with additional backslashes (\\dfs\\Path-Dir) in my path, even when using [regex]::escape.

How can I use an array of the different paths to match against the $CurrPath and perform the replace? I know it doesn't work, but like this:

If ($Array -in $CurrPath) {
    $NewPath = $CurrPath.Replace($Array, "dfs\Path-Dir"
}
Matt
  • 45,022
  • 8
  • 78
  • 119
Harshmage
  • 23
  • 6
  • What you are replacing it with is always the same? Or is the replacement different depending on what it matched? – Matt Jan 26 '16 at 17:59
  • You have the right idea with regex but you execution is flawed if you are getting extra characters.. You dont need to escape the replacement string just the match string. – Matt Jan 26 '16 at 18:08
  • It's always the same, the server share was directly copied to the DFS share, so other than the initial share folder (`oldNUMsrv\path_dir` and `dfs\Path-Dir`), it's a like-for-like folder structure. – Harshmage Jan 26 '16 at 18:09
  • Can you show me an example of a string and expected output. Also I would like to see an example of how you used regex. I think I know where you might have gone wrong. Would be better if I had something concrete to test with – Matt Jan 26 '16 at 18:18
  • small example: `"C:\temp\atr elementary\VIDEO_TS.IFO" -replace [regex]::escape("temp\atr elementary"), "another\path"` returns `C:\another\path\VIDEO_TS.IFO`. Depending though you might be able to use cmdlets instead of regex. – Matt Jan 26 '16 at 18:29
  • What's with all the if/elseif statements? Why not just `$CurrPath -split '\\' -contains 'path_dir'`? – Mathias R. Jessen Jan 26 '16 at 18:53
  • @Matt, go ahead and post that as the answer, because that got it. – Harshmage Jan 26 '16 at 23:26

1 Answers1

0

I think your issue might have been assuming you had to escape the replacement string as well as the pattern string. That is not the case. Since you have control characters (the slash) you will need to escape the pattern string. In it's basic form you just need to do something like this:

PS C:\Users\Matt> "C:\temp\test\file.php" -replace [regex]::Escape("temp\test"), "another\path"
C:\another\path\file.php

However I would like to take this one step further. Your if statements are all doing relatively the same thing. Finding a series of strings and replacing them all with the same thing. -contains isn't really necessary either. Also note that all of those comparison operators are case insensitive by default. See about_comparison_operators

You can simplify all that with a little more regex by building a pattern string. So assuming that your strings are all unique (case does not matter) you could do this:

$stringstoReplace = "oldNUMsrv1\path_dir", "oldNUMsrv2\Path_dir", "oldNUMsrv1\Path_Dir"
$regexPattern = ($stringstoReplace | ForEach-Object{[regex]::Escape($_)}) -join "|"

if($CurrPath -match $regexPattern){
     $NewPath = $CurrPath -replace $regexPattern,"new\path"
} 

You don't even need the if. You could just use -replace on all strings regardless. I only left the if since you had a check to see if something changed. Again, if you were just creating all those statements just to account for case then my suggestion is moot.

Matt
  • 45,022
  • 8
  • 78
  • 119