This is easy.

$i = 10
$string = " " * $i

But sometimes you need a different approach. What I was doing recently was searching for some code and wanting to wrap it in other code at the correct indent level.

At first I tried to count how many spaces were at the beginning of each string and generate my own. This didn't work because in the real world tabs and spaces get intermixed and it's not clear how many spaces a tab will translate to. My solution was to "capture" all of the whitespace at the start of the line I was going to wrap, and re-use it.

I did this by trimming the start of a string (which removes both spaces and tabs), and counting the difference in lengths from old and new strings, then getting just that substring of the line to use for whitespace:

$whiteSpace = $line.Substring(0, $line.Length - $line.TrimStart().Length)
$outputLine = "$($whiteSpace)My Code..."

It might be useful to show how I used this in the real world. I admit this is not a fancy way of doing things and doesn't use regex, but it is what it is. It began with C# code which had a bug:

public class Sample {
    public static void Main()
    {
        int a = 0;
        int b = 1;
        bool safeToDivide = true;

        if (safeToDivide)
        {
            int c = a / b; // Safe
        }

        safeToDivide = false;

        // The test is missing
        int d = b / a; // Divide by zero
    }
}

So from a well-defined format lots of code needed to be wrapped in a test, and others were already wrapped in a test. I wanted to wrap the unwrapped code with a test and retain the correct indent levels. Here's the PowerShell I came up with (again, highly specialised for this scenario and I was able to confirm all the changes it made in source control before committing it to production):

Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
$nl = [Environment]::NewLine

$searchString = "*=*/*" # something = a / b
$searchWrapper = "*if*safeToDivide*" # if (safeToDivide)
$wrapper = "if (safeToDivide)"

$fileList = @{}
Get-ChildItem -Path "C:\Temp" -Recurse Sample.cs | %{
	$fileList[$_] = Get-Content $_
}

$fileList.Keys | %{
	$fileName = $_.FullName
	Write-Output "Processing $fileName"
	$fileData = Get-Content $fileName
	$fileOutput = @()

	$updated = $false
	for ($i = 0; $i -lt $fileData.Length; $i++) {
		# -2 assumes the wrapper will be two lines above, i.e. brackets have their own line.
	    if ($fileData[$i] -like $searchString -and $fileData[$i - 2] -notlike $searchWrapper) {
	      	$whiteSpace = $fileData[$i].Substring(0, $fileData[$i].Length - $fileData[$i].TrimStart().Length)

	      	$fileOutput += "$($whiteSpace)$($wrapper)"
	      	$fileOutput += "$($whiteSpace){"
	      	$fileOutput += "`t$($fileData[$i])"
	      	$fileOutput += "$($whiteSpace)}"

			$updated = $true
	    } else {
	    	$fileOutput += $fileData[$i]
	    }
	}

	if ($updated) {
		Write-Host "Updated $fileName"
		Set-Content -Path $fileName -Value $fileOutput
	}
}

Which resulted in a file like this:

public class Sample {
    public static void Main()
    {
        int a = 0;
        int b = 1;
        bool safeToDivide = true;

        if (safeToDivide)
        {
            int c = a / b; // Safe
        }

        safeToDivide = false;

        // The test is missing
        if (safeToDivide)
        {
            int d = b / a; // Divide by zero
        }
    }
}

Here's hoping that helps someone, somewhere.