PowerShell script not running

BeckoningEagle

New Member
I am trying to run this powershell script at the end of my installation, what it does is replace the computer name with a prefix and some of the octets of the IP address. This is for a very specific need. Assume that the user configured for this task has been secured in a way that can only be used for this specific task. I am aware that storing the password in a script in plain text is not ideal. The script runs fine when running interactively, but it doesn't seem to run at all when placing it as a file in the Before Logon section of the install. I also tried after logon. Any help will be appreciated:

#----BEGINNING OF SCRIPT----------------------------------
# Unsecure Credentials

$Password = ConvertTo-SecureString 'ThePa$$word' -AsPlainText -Force
$UserCredential = New-Object System.Management.Automation.PSCredential ('DOMAIN\TheUser', $Password)

#Generate the new computername, appending the middle 2 octets of the IP Address

$currentIP = (Get-NetIPAddress -AddressFamily IPv4 | Where-Object { $_.InterfaceAlias -notlike '*Loopback*' -and $_.PrefixOrigin -ne 'WellKnown' }).IPAddress
$computerName = "TPR-"


if ($currentIP -ne $null)
{
$modifiedIP = $currentIP.Substring(3)
$modifiedIP = $modifiedIP.replace('.', '-')

$computerName = $computerName + $modifiedIP
}

# Start a new PowerShell session with the provided credentials
Start-Process powershell -Credential $UserCredential -ArgumentList '-NoProfile -Command "Rename-Computer -NewName $computerName"'
Restart-Computer -Force

#-------END OF SCRIPT---------------------------
 
Last edited:
How about configuring static IP address OR DHCP Reservation? This way you can preset the computer name in unattend XML without dynamically generating it via PowerShell.
 
How about configuring static IP address OR DHCP Reservation? This way you can preset the computer name in unattend XML without dynamically generating it via PowerShell.
This is for a massive deployment. DHCP or Static IP reservations are not an option for this scenario.
 
Last edited:
This is for a massive deployment. DHCP or Static IP's reservations are not an option for this scenario.
1) If this is for "massive deployment", I think you should re-consider your strategy from the ground up, since "Rename-Computer" requires administrative user rights and Admin Approval Mode (i.e., you must click "Yes" at the UAC prompt) if you run in "After Logon". A standard user in a domain environment cannot rename computers. Also, when the IP changes again (since it is DHCP), do you run the script again? If not, then it is meaningless to co-relate the two in the first place because they will still be different later.

2) If this is for "massive deployment", then I think you should be deploying AD and DNS in your company. DNS locates computers without first knowing the IP addresses, so I do not see why the computer name needs to be coupled with IP address when you can simply perform nslookup and gather the IP address at run time.

3) If this is for "massive deployment", and this configuration is required to work with an application, then the application should be modified and query the DNS at run time, instead of relying on static information like the computer name.

I have deployed tens of thousands of computers for multi-national investment bank in the past and we did not have such strange and unreliable strategy on computer names. Sorry if this offends you, but I think I need to state the obvious from the security and "massive deployment" point of view.
 
Let's begin with the actual script:

1. When any script (or command) runs in Post-Setup (Machine) or "Before logon", it runs under SYSTEM context. Therefore it doesn't require elevation through provided credentials.

2. Running Start-Process without -Wait, forces your Rename-Computer command to run in the background. This creates a race condition, where Restart-Computer can trigger before your child process has taken action. Since you don't need a separate process (as SYSTEM), you can simply call Rename and then Restart.

3. Rename-Computer requires a restart to make it take effect. Generally that's a bad habit during Post-Setup (Machine) because after restarting, Windows doesn't resume the next command in the SetupComplete wrapper script. It's not like the specialize phase, where you're allowed to reboot in between commands.

The restart puts you right at the first logon screen. If this script is the last command in (Machine) mode, then it's acceptable.

How would I solve this problem? Not everyone has the benefit of a MDM or a managed back-end. If you have to locally rename PC's, then move your script (minus the credentials part), to the specialize pass using a stub autounattend.xml.

1. Make a new folder in the ISO directory:
\sources\$OEM$\$1\Scripts

2. Copy your new script there.
Code:
#----BEGINNING OF SCRIPT----------------------------------
#Generate the new computername, appending the middle 2 octets of the IP Address

$currentIP = (Get-NetIPAddress -AddressFamily IPv4 | Where-Object { $_.InterfaceAlias -notlike '*Loopback*' -and $_.PrefixOrigin -ne 'WellKnown' }).IPAddress
$computerName = "TPR-"

if ($currentIP -ne $null)
{
    $modifiedIP = $currentIP.Substring(3)
    $modifiedIP = $modifiedIP.replace('.', '-')
 
    $computerName = $computerName + $modifiedIP
}

Rename-Computer -NewName $computerName
Restart-Computer -Force

#-------END OF SCRIPT---------------------------

3. Copy this autounattend.xml to the ISO:
Code:
<?xml version="1.0" encoding="utf-8"?>
<unattend xmlns="urn:schemas-microsoft-com:unattend">
    <settings pass="windowsPE">
        <component name="Microsoft-Windows-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <UserData>
                <ProductKey>
                    <Key></Key>
                </ProductKey>
            </UserData>
        </component>
    </settings>
    <settings pass="specialize">
        <component name="Microsoft-Windows-Deployment" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <RunSynchronous>
                <RunSynchronousCommand wcm:action="add">
                    <Description>Rename PC</Description>
                    <Order>1</Order>
                    <Path>powershell -NoProfile -ExecutionPolicy Bypass -f C:\Scripts\rename-script.ps1</Path>
                    <WillReboot>Always</WillReboot>
                </RunSynchronousCommand>
            </RunSynchronous>
    </settings>
</unattend>


Alternatively, Post-Setup (User) or "After logon" scripts also run with Administrator privileges. So you don't need other credentials. The bad side is rebooting after the first desktop logon is a bad user experience, unless you inform the user that's normal for this deployment.

Logon, wait for the restart, then logon again.
 
Thank you, Annie, for your suggestions. I do not take offense at your comment. I do think you assume too much, and you are also wrong on point #1, you do not necessarily get prompted for changing a computer name if you have the rights to do so. We are mostly doing this for aesthetics and a proof of concept. If it pans out then we have nice looking names, joined in a specific container, that at a glance, without having to even log into the network, tells us the location of the Kiosk. I know there are many ways to skin a cat, this naming convention for this specific project has value for us. If it doesn't pan out then we just go with our regular naming convention and monitoring tools and nothing happens.
 
Let's begin with the actual script:

1. When any script (or command) runs in Post-Setup (Machine) or "Before logon", it runs under SYSTEM context. Therefore it doesn't require elevation through provided credentials.

2. Running Start-Process without -Wait, forces your Rename-Computer command to run in the background. This creates a race condition, where Restart-Computer can trigger before your child process has taken action. Since you don't need a separate process (as SYSTEM), you can simply call Rename and then Restart.

3. Rename-Computer requires a restart to make it take effect. Generally that's a bad habit during Post-Setup (Machine) because after restarting, Windows doesn't resume the next command in the SetupComplete wrapper script. It's not like the specialize phase, where you're allowed to reboot in between commands.

The restart puts you right at the first logon screen. If this script is the last command in (Machine) mode, then it's acceptable.

How would I solve this problem? Not everyone has the benefit of a MDM or a managed back-end. If you have to locally rename PC's, then move your script (minus the credentials part), to the specialize pass using a stub autounattend.xml.

1. Make a new folder in the ISO directory:
\sources\$OEM$\$1\Scripts

2. Copy your new script there.
Code:
#----BEGINNING OF SCRIPT----------------------------------
#Generate the new computername, appending the middle 2 octets of the IP Address

$currentIP = (Get-NetIPAddress -AddressFamily IPv4 | Where-Object { $_.InterfaceAlias -notlike '*Loopback*' -and $_.PrefixOrigin -ne 'WellKnown' }).IPAddress
$computerName = "TPR-"

if ($currentIP -ne $null)
{
    $modifiedIP = $currentIP.Substring(3)
    $modifiedIP = $modifiedIP.replace('.', '-')
 
    $computerName = $computerName + $modifiedIP
}

Rename-Computer -NewName $computerName
Restart-Computer -Force

#-------END OF SCRIPT---------------------------

3. Copy this autounattend.xml to the ISO:
Code:
<?xml version="1.0" encoding="utf-8"?>
<unattend xmlns="urn:schemas-microsoft-com:unattend">
    <settings pass="windowsPE">
        <component name="Microsoft-Windows-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <UserData>
                <ProductKey>
                    <Key></Key>
                </ProductKey>
            </UserData>
        </component>
    </settings>
    <settings pass="specialize">
        <component name="Microsoft-Windows-Deployment" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <RunSynchronous>
                <RunSynchronousCommand wcm:action="add">
                    <Description>Rename PC</Description>
                    <Order>1</Order>
                    <Path>powershell -NoProfile -ExecutionPolicy Bypass -f C:\Scripts\rename-script.ps1</Path>
                    <WillReboot>Always</WillReboot>
                </RunSynchronousCommand>
            </RunSynchronous>
    </settings>
</unattend>


Alternatively, Post-Setup (User) or "After logon" scripts also run with Administrator privileges. So you don't need other credentials. The bad side is rebooting after the first desktop logon is a bad user experience, unless you inform the user that's normal for this deployment.

Logon, wait for the restart, then logon again.
I will give this a whirl. We can't use the local admin because the computer is domain joined so it needs an account of a user that can rename the computer object. This is a good starting point, thank you.
 
The traditional answer is renaming the PC, and reboot (in a script) before it does a domain join. This avoids the credential headache.
 
you do not necessarily get prompted for changing a computer name if you have the rights to do so.
I think what you mean is the built-in 'Administrator" account, which bypasses Admin Approval Mode by default. Yet Windows disables this built-in Administrator account by default for security reasons.
 
Thank you, Annie, for your suggestions. I do not take offense at your comment. I do think you assume too much, and you are also wrong on point #1, you do not necessarily get prompted for changing a computer name if you have the rights to do so. We are mostly doing this for aesthetics and a proof of concept. If it pans out then we have nice looking names, joined in a specific container, that at a glance, without having to even log into the network, tells us the location of the Kiosk. I know there are many ways to skin a cat, this naming convention for this specific project has value for us. If it doesn't pan out then we just go with our regular naming convention and monitoring tools and nothing happens.
If you are trying out the concept of a Kiosk, you may have a look at "Windows Configuration Designer" that has Kiosk profiles for Windows.
 
After some testing, I added the following scripts, which you can run with admin credentials (such as the "Specialize" pass during OOBE), to add a scheduled task to rename computer.

XML:
    <settings pass="specialize">
        <component name="Microsoft-Windows-Deployment" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <RunSynchronous>
                <RunSynchronousCommand wcm:action="add">
                    <Path>PowerShell.exe -ExecutionPolicy Bypass -File C:\Scripts\RenameComputer.ps1</Path>
                    <Order>1</Order>
                </RunSynchronousCommand>
            </RunSynchronous>
        </component>
    </settings>

The scheduled task would run every time when a user logs on, and runs with "Local System" credential, so no other admin credentials need to be embedded in the file.

Code:
#----BEGINNING OF SCRIPT----------------------------------
#Generate the new computername, appending the last 3 octets of the IP Address
$taskName = 'Rename Computer'
$taskDescription = 'Rename Computer'
$action = New-ScheduledTaskAction -Execute 'Powershell.exe' -Argument "-Command `" & {
    `$currentIP = (Get-NetIPAddress -AddressFamily IPv4 | Where-Object { `$_.InterfaceAlias -notlike '*Loopback*' -and `$_.PrefixOrigin -ne 'WellKnown' }).IPAddress;
    if (`$null -ne `$currentIP) {
        `$targetComputerName = 'TPR-' + `$currentIP.split('.', 2)[1].replace('.', '-')
    };
    Rename-Computer -NewName `$targetComputerName
}`""
$trigger = New-ScheduledTaskTrigger -AtLogon
$settings = New-ScheduledTaskSettingsSet
Register-ScheduledTask -Action $action -Trigger $trigger -TaskName $taskName -Description $taskDescription -Settings $settings -User 'System'
#-------END OF SCRIPT---------------------------

You may schedule your reboots for the changes to take effect at a later time, such as at mid-night every day, so that the user experience is not hindered due to sudden reboots, and the changes reflect the latest IP address assignments and update every day.

Of course, if you want immediate reboots, you may schedule the "Restart-Computer" command as well.

I suggest you take a look at the "Scheduled Task" PowerShell scripts to optimize user experience while keeping ComputerName and IP address in sync.
 
Last edited:
Thanks Annie and Garlin for your help in this matter. Doing it through the stub unattend worked like a charm. I copied the file to the OEM folder as per Garlins sugggestion and then modified the autounattend.xml file with:

XML:
<settings pass="specialize">
        <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <ProductKey>NPPR9-FWDCX-D2C8J-H872K-2YT43</ProductKey>
        </component>
        <component name="Microsoft-Windows-Deployment" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <RunSynchronous>
            <RunSynchronousCommand wcm:action="add">
                <Order>1</Order>
                <Path>powershell.exe -ExecutionPolicy Bypass -File %SYSTEMROOT%\Scripts\generateComputerName.ps1</Path>
                <Description>Set computer name</Description>
                <WillReboot>Always</WillReboot>
            </RunSynchronousCommand>
        </RunSynchronous>
        </component>
        <component name="Microsoft-Windows-UnattendedJoin" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <Identification>
                <JoinDomain>domain.name</JoinDomain>
                <MachineObjectOU>OU=theout, OU=Computer Objects, DC=domain, DC=name</MachineObjectOU>
                <TimeoutPeriodInMinutes>15</TimeoutPeriodInMinutes>
                <UnsecureJoin>false</UnsecureJoin>
                <Credentials>
                    <Domain>domain.name</Domain>
                    <Password></Password>
                    <Username>userwithrights</Username>
                </Credentials>
            </Identification>
        </component>
    </settings>

I may get rid of the Domain Join and have the on-site tech do the join after install to avoid having credentials. But, it works.

Thank You .
 
Back
Top