#StackBounty: #windows #powershell #windows-server-2016 #winrm #window-server-2012 Where is WinRMRemoteWMIUsers__ local group in Window…

Bounty: 200

With Windows Server 2012 R2 I can use the group WinRMRemoteWMIUsers__ to enable remote PowerShell execution via -CimSession for non-admin users. However, the group is missing on my Windows Server 2016 machines and I do not see any replacement for it except the Remote Management Users group. However it seems to me that it grants wider permissions than WinRMRemoteWMIUsers__.

Where is the WinRMRemoteWMIUsers__ group in Windows Server 2016?

Get this bounty!!!

#StackBounty: #powershell #csom #project-server Get Selection from Lookup Table CSOM PowerShell in Project Server

Bounty: 50

I have a custom field at the project level that is a lookup table (single select). I cannot for the life of me figure out how to get the value of the selection from the lookup table. I can get the lookup table:

$lookupTables = $projContext.LookupTables

$myLookupTable = $lookupTables.GetByGuid('GUID FOR LOOKUP TABLE')

and I can get the field:
$custFields = $project.CustomFields

$myField = $custFields.GetByGuid([Guid]"{GUID FOR FIELD}") 
$projContext.Load($myField )

When I look at values in myField everything looks ok. I can see the .LookupDefaultValue but when I try to get the selection of the Field, I’m not quite sure what to do. I’ve Tried:

$myfieldvalue = new-object Microsoft.SharePoint.Client.FieldUserValue($myField).LookupValue

But it comes out as Microsoft.SharePoint.Client.FieldUserValue

I’ve tried

$myfieldvalue = $myField .Value
$projContext.Load($myfieldvalue )

but that blows up on the Load.

Get this bounty!!!

#StackBounty: #powershell #azure #azure-cloud-services #antimalware Setting Anti-Malware Enabled as default on Azure Cloud Service

Bounty: 50

OK, so this is a revised post as I can see some down-votes and the solution, for me, is still not working. As a background, deploying from Visual Studio to a Cloud Service in Azure will reset anti-malware back to original state (disabled). So I am trying to enable this by default.

Steps taken so far:

  1. Create Startup folder in the main web project
  2. Add to this folder startup.cmd file with the following:
    Powershell -ExecutionPolicy Unrestricted .Startupstartup.ps1 >> "c:logsstartup_ps_log.txt"
  1. Add to the same folder the powershell script startup.ps1:
    Set-AzureServiceAntimalwareExtension -ServiceName "myservicename" -AntimalwareConfiguration -Slot "Production"
  1. Modify the ServiceDefinition.csdef file in the Cloud Service project to call the startup task:
    <Startup priority="-2">
        <Task commandLine="startupstartup.cmd" executionContext="elevated" taskType="background" />      

I deploy my solution and get the same result. Anti-malware is still disabled. If I fire up an RDP session into the VM and interrogate the log I can see it is running but failing to find the specific powershell command/script for AzureServiceAntimalwareExtension:

    Set-AzureServiceAntimalwareExtension : The term 
    'Set-AzureServiceAntimalwareExtension' is not recognized as the name of a 
    cmdlet, function, script file, or operable program. Check the spelling of the 
    name, or if a path was included, verify that the path is correct and try again.

Any suggestions?

Get this bounty!!!

#StackBounty: #powershell #powershell-v4.0 #powershell-remoting Constrained endpoint on specific user

Bounty: 50

I’m trying to create a PowerShell endpoint constraint that restricts an user to only execute the functions in a custom module I made.

The first thing I did is import-module mymodule.psm1 which allows me to run my modules fine withing my host system.

Then the following PS command creates the configuration file for the endpoint which allows the functions inside the brackets to be the only functions the user gets to execute.

New-PSSessionConfigurationFile -VisibleFunctions('Get-Command','Get-Info', 'CreateAD-User','Generate-Html','Change-Logon') -LanguageMode ‘ConstrainedLanguage’ –SessionType ‘RestrictedRemoteServer’ –Path ‘c:testhelpdesk.pssc’

Then I register the endpoint with

Register-PSSessionConfiguration –Name ‘HelpDesk’ -ShowSecurityDescriptorUI –Path ‘c:testhelpdesk.pssc’

and selected which user I want allow to have these constrains once the SecurityDescriptorUI pops up. Once I log into the user that I set up the constrains for with

Enter-PSSession -computername SRV1-AD -Credential $credential -ConfigurationName HelpDesk

These are the allowed cmdlets / functions that the user is allowed to execute. These are the default required cmdlets to allow remote connections into a system.


How can I allow my custom module to be the only functions the endpoint allows users to execute? or How can I import my module into configuration file so it executes every time the HelpDesk end point configuration is used. I know that in the configuration file there’s a line to import modules but Import-Module is not actually a module an example of a module would be ActiveDirectory, if I’m able to find what module import-module is a part of I think I should be able to do a quick and dirty work around for this.


A dirty solution I found for this was to enter into the user’s session and disable all cmdlets / functions except the ones I want to allowed for example import-module & Get-Command with import-module I can manually import my custom module and my functions will be the only ones visible to user. But this is not a perfect solution because this means that I would need to download my module into every system I want this to take effect and it’s no longer a one to many solution. The ideal solution is to have my module locally stored, enter into a session with the registered end point and have my module already imported into the users account.

Enter-PSSession -computername SRV1-AD -Credential $credential -ConfigurationName HelpDesk

Further Update

User @prasoon-karunan-v suggested I used -ScriptsToProcess & FunctionDefinitions to import the module so I used the following command

New-PSSessionConfigurationFile -VisibleFunctions('Get-Command','Get-Info', 'CreateAD-User','Generate-Html','Change-Logon') -LanguageMode ‘ConstrainedLanguage’ –SessionType ‘RestrictedRemoteServer’ –Path ‘.EndPoint.pssc’ -ScriptsToProcess C:UsersAdministratorDesktopModulesImportM.psm1

In the configuration file I also set the functions I want to use like so

# Functions defined in this session configuration
FunctionDefinitions = 'Get-Command','Get-Info', 'CreateAD-User','Generate-Html','Change-Logon'

When I tried to establish a session it would throw the following error


Then I thought maybe it’s not working because were not telling the command to import anything were just pointing to the module file, so maybe I need to create a small script that imports the module then add it the configuration file. So that’s exactly what I did I created a small script with just,
import-module C:ModulesImportM.psm1 and then I went over to the .pssc
file and added this script to the ScriptsToProcess but I get the following error after I try to establish a session to the constrained endpoint.


Language Mode is set to

LanguageMode = 'RestrictedLanguage'

Get this bounty!!!

#StackBounty: #c# #windows #powershell #usb-drive #computer-forensics How can I get timestamps on previously connected USB devices?

Bounty: 50

I’m trying to get an old PowerShell script to show the times of previously connected USB devices. After having read a few forensics blogs like this, I found this script from this blog. (Script by Jason Walker.)

Unfortunately it doesn’t show any timestamps or any other useful details about the devices. So I was hoping there should be a way to get that too. Only I fail to see how to incorporate this.

Function Get-USBHistory { 

 Begin { 
     $TempErrorAction = $ErrorActionPreference 
     $ErrorActionPreference = "Stop" 
     $Hive   = "LocalMachine" 
     $Key    = "SYSTEMCurrentControlSetEnumUSBSTOR" 

     $USBDevices      = @() 
     $ComputerCounter = 0         

     ForEach($Computer in $ComputerName) 
        $USBSTORSubKeys1 = @() 
        $ChildSubkeys    = @() 
        $ChildSubkeys1   = @() 

        $Computer = $Computer.Trim().ToUpper() 
        Write-Progress -Activity "Collecting USB history" -Status "Retrieving USB history from $Computer" -PercentComplete (($ComputerCounter/($ComputerName.Count)*100)) 

           If(-not (Test-Connection -ComputerName $Computer -Count 1 -Quiet)) 
              Write-Warning "Ping failed on $Computer" 
        }#end if ping  

            $Reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($Hive,$Computer) 
            $USBSTORKey = $Reg.OpenSubKey($Key) 
            $USBSTORSubKeys1  = $USBSTORKey.GetSubKeyNames() 
         }#end try              
            Write-Warning "There was an error connecting to the registry on $Computer or USBSTOR key not found. Ensure the remote registry service is running on the remote machine." 
         }#end catch 

         ForEach($SubKey1 in $USBSTORSubKeys1) 
            $ErrorActionPreference = "Continue" 
            $Key2 = "SYSTEMCurrentControlSetEnumUSBSTOR$SubKey1" 
            $RegSubKey2  = $Reg.OpenSubKey($Key2) 
            $SubkeyName2 = $RegSubKey2.GetSubKeyNames() 

            $ChildSubkeys   += "$Key2$SubKeyName2" 
         }#end foreach SubKey1 

         ForEach($Child in $ChildSubkeys) 

            If($Child -match " ") 
               $BabySubkey = $null 
               $ChildSubkey1 = ($Child.split(" "))[0] 

               $SplitChildSubkey1 = $ChildSubkey1.split("") 

               0..4 | Foreach{ [String]$BabySubkey += ($SplitChildSubkey1[$_]) + ""}  

               $ChildSubkeys1 += $BabySubkey + ($Child.split(" ")[-1]) 
               $ChildSubkeys1 += $ChildSubkey1 

               $ChildSubkeys1 += $Child 
         }#end foreach ChildSubkeys 

         ForEach($ChildSubkey1 in $ChildSubkeys1) 
            $USBKey      = $Reg.OpenSubKey($ChildSubkey1) 
            $USBDevice   = $USBKey.GetValue('FriendlyName')  
               $USBDevices += New-Object -TypeName PSObject -Property @{ 
                     USBDevice = $USBDevice 
                     Computer  = $Computer 
                     Serial    = $ChildSubkey1.Split("")[-1] 
          }#end foreach ChildSubKey2 

         #Display results         
     $USBDevices | Select Computer,USBDevice,Serial 
     }#end foreach computer  

  }#end process 

     #Set error action preference back to original setting         
     $ErrorActionPreference = $TempErrorAction          

}#end function 

And the C# code:

using System;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using Microsoft.Win32;
using Microsoft.Win32.SafeHandles;
class Program
    static void Main(string[] args)
        string usbStor = @"SYSTEMControlSet001EnumUSBSTOR";
        using (var keyUsbStor = Registry.LocalMachine.OpenSubKey(usbStor))
            var usbDevices = from className in keyUsbStor.GetSubKeyNames()
                             let keyUsbClass = keyUsbStor.OpenSubKey(className)
                             from instanceName in keyUsbClass.GetSubKeyNames()
                             let keyUsbInstance = new RegistryKeyEx(keyUsbClass.OpenSubKey(instanceName))
                             select new
                                 UsbName = keyUsbInstance.Key.GetValue("FriendlyName"),
                                 ConnectTime = keyUsbInstance.LastWriteTime
            foreach (var usbDevice in usbDevices.OrderBy(x => x.ConnectTime))
                Console.WriteLine("({0}) -- '{1}'", usbDevice.ConnectTime, usbDevice.UsbName);
/// <summary>
/// Wraps a RegistryKey object and corresponding last write time.
/// </summary>
/// <remarks>
/// .NET doesn't expose the last write time for a registry key 
/// in the RegistryKey class, so P/Invoke is required.
/// </remarks>
public class RegistryKeyEx
    #region P/Invoke Declarations
    // This declaration is intended to be used for the last write time only. int is used
    // instead of more convenient types so that dummy values of 0 reduce verbosity.
    [DllImport("advapi32.dll", EntryPoint = "RegQueryInfoKey", CallingConvention = CallingConvention.Winapi, SetLastError = true)]
    extern private static int RegQueryInfoKey(
        SafeRegistryHandle hkey,
        int lpClass,
        int lpcbClass,
        int lpReserved,
        int lpcSubKeys,
        int lpcbMaxSubKeyLen,
        int lpcbMaxClassLen,
        int lpcValues,
        int lpcbMaxValueNameLen,
        int lpcbMaxValueLen,
        int lpcbSecurityDescriptor,
        IntPtr lpftLastWriteTime);
    #region Public Poperties
    /// <summary>
    /// Gets the registry key owned by the info object.
    /// </summary>
    public RegistryKey Key { get; private set; }
    /// <summary>
    /// Gets the last write time for the corresponding registry key.
    /// </summary>
    public DateTime LastWriteTime { get; private set; }
    /// <summary>
    /// Creates and initializes a new RegistryKeyInfo object from the provided RegistryKey object.
    /// </summary>
    /// <param name="key">RegistryKey component providing a handle to the key.</param>
    public RegistryKeyEx(RegistryKey key)
        Key = key;
    /// <summary>
    /// Creates and initializes a new RegistryKeyInfo object from a registry key path string.
    /// </summary>
    /// <param name="parent">Parent key for the key being loaded.</param>
    /// <param name="keyName">Path to the registry key.</param>
    public RegistryKeyEx(RegistryKey parent, string keyName)
        : this(parent.OpenSubKey(keyName))
    { }
    /// <summary>
    /// Queries the currently set registry key through P/Invoke for the last write time.
    /// </summary>
    private void SetLastWriteTime()
        Debug.Assert(Key != null, "RegistryKey component must be initialized");
        GCHandle pin = new GCHandle();
        long lastWriteTime = 0;
            pin = GCHandle.Alloc(lastWriteTime, GCHandleType.Pinned);
            if (RegQueryInfoKey(Key.Handle, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pin.AddrOfPinnedObject()) == 0)
                LastWriteTime = DateTime.FromFileTime((long)pin.Target);
                LastWriteTime = DateTime.MinValue;
            if (pin.IsAllocated)

(Sorry, I can’t get the PSH code to highlight correctly.)

How can I use this to improve the script?

Update: 2017-11-06

Following @iRon’s suggestion, I tried to directly access the registry path: HKLMSYSTEMCurrentControlSetEnumUSBSTOR<drive>Propertie‌​s, using RegEdit, but then I got a permission error, which is strange, as my user account is Admin. (This is on Win8.1)

enter image description here

Get this bounty!!!

#StackBounty: #2013 #development #powershell #custom-permission-level which SPRoleDefinition.BasePermissions responsible to mark discus…

Bounty: 50

I have the following inside my sharepoint on-premises 2013 farm:-

  1. Team site collection, which have the publishing featured enabled.
  2. Inside the Team site collection, i added a Discussion Board list.
  3. Now users with built-in Contribute permissions, can add,edit, delete discussion board items.
  4. But seems they can not mark their own or other users items as featured, where this option is only available to site admins:-
    enter image description here

so i am planning to create a custom permission level using power-shell, which have the exact permission as the built-in Contribute, but with the ability to mark Discussion Board items as featured. so i am not sure which SPRoleDefinition.BasePermissions is responsible to enable marking items as featured? now i find this link which list the available permissions, but i can not find the permission to allow “Mark as featured”??

Get this bounty!!!

#StackBounty: #powershell #designer-workflow #csom #pnp-powershell Copying a 2013 platform list SPD workflow between sites using PowerS…

Bounty: 50

I am trying to copy a List workflow from one site to another (same site collection). Unfortunately, for various reasons I can’t save the workflow as a template.

I have a PowerShell script that does almost everything, but is missing one component.

The below script will get the workflow from a source site, get the definition, then replace all the list GUIDs for those in the new site (sites have the same structure).

It will then create a new workflow in the target site, associate it to the correct list, and publish it. The workflow performs perfectly.

There is only one problem – if I go into SharePoint Designer and connect to the new site, if I Publish the workflow again (or make a change and publish it), a second subscription is created on the site.

Before Publishing:

After Publishing:

Can anyone see a way around this? Script pasted below:

function Copy-Workflow {

    switch ($Environment){
            $rootURL = "https://xxx.sharepoint.com/sites/db"
            $sourceSite = $SourceAKPA
            $rootURL = "https://xxx.sharepoint.com/sites/db-test"
            $sourceSite = $SourceAKPA
            $rootURL = "https://xxx.sharepoint.com/sites/db-dev"
            $sourceSite = $SourceAKPA
            $rootURL = "https://xxx.sharepoint.com/sites/db-sandpit"
            $sourceSite = $SourceAKPA
    $errors = $false
    $sourceSiteURL = "$rootURL/$sourceSite"

    Connect-PnPOnline -Url $sourceSiteURL -Credentials dbadmin

        $SourceTable = Get-PnPList
        $SourceWorkflowDefn = Get-PnPWorkflowDefinition -PublishedOnly
        $SourceWorkflowSub = Get-PnPWorkflowSubscription 


    Connect-PnPOnline -Url "$rooturl/$targetAKPA" -Credentials dbadmin 

        $DestTable = Get-PnPList
        $DestWorkflowDefn = Get-PnPWorkflowDefinition -PublishedOnly
        $DestWorkflowSub = Get-PnPWorkflowSubscription

        $sourceDefn = $SourceWorkflowDefn | Where-Object{$_.DisplayName -eq $Workflow}
        $sourceSubs = $SourceWorkflowSub | Where-Object{$_.Name -eq $Workflow}
        if($sourceDefn -ne $null){
            $sourceXAML = $sourceDefn.Xaml

            foreach ($id in $SourceTable){

                if($sourceXAML -match $id.id.Guid){
                    $sourceIDName = $SourceTable | Where-Object{$_.ID.Guid -eq $id.id.Guid} | Select-Object Title
                    $destIDNumber = $DestTable | Where-Object{$_.Title -eq $sourceIDName.Title} | Select-Object Id

                    $sourceXAML = $sourceXAML.Replace($Id.id.guid,$destIDNumber.id.Guid)


        } else {
        Write-Host "Workflow $workflow not found in source site" -ForegroundColor Red
        $errors = $true

        if ($errors -ne $true){
            $destDefn = $DestWorkflowDefn | Where-Object{$_.DisplayName -eq $Workflow}
            if($destDefn -ne $null){
                #$destXAML = $sourceXAML
                #$destDefn.Xaml = $destXAML
                Write-Host "Removing old definition"-ForegroundColor Yellow
                Remove-PnPWorkflowDefinition -Identity $destDefn

            #Write-Host "Workflow $workflow not found in destination site" -ForegroundColor Red
            # Load the WorkflowServicesManager client library (please provide the proper file path …)
            Add-Type -Path (Resolve-Path "$env:CommonProgramFilesMicrosoft SharedWeb Server Extensions16ISAPIMicrosoft.SharePoint.Client.dll")
            Add-Type -Path (Resolve-Path "$env:CommonProgramFilesMicrosoft SharedWeb Server Extensions16ISAPIMicrosoft.SharePoint.Client.Runtime.dll")
            Add-Type -Path (Resolve-Path "$env:CommonProgramFilesMicrosoft SharedWeb Server Extensions16ISAPIMicrosoft.SharePoint.Client.WorkflowServices.dll")

            # Set the target SharePoint Site
            $SiteURL =  "$rooturl/$targetAKPA"

            # Set up credentials

            $Creds = Get-PnPStoredCredential -Name DBAdmin -Type PSCredential

            # Create Context

            $ClientContext = New-Object Microsoft.SharePoint.Client.ClientContext($SiteUrl)
            $credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($creds.UserName, $creds.Password)
            $ClientContext.Credentials = $credentials
            $spWeb = $ClientContext.Web

            # Create a WorkflowServicesManager instance and retrieve WorkflowService related objects

            $WorkflowServicesManager = New-Object Microsoft.SharePoint.Client.WorkflowServices.WorkflowServicesManager($ClientContext,$spWeb)
            $WorkflowSubscriptionService = $WorkflowServicesManager.GetWorkflowSubscriptionService()
            $WorkflowInstanceService = $WorkflowServicesManager.GetWorkflowInstanceService()

            # Create a WorkflowServicesManager instance

            # Get a reference to the Workflow Deployment Service

            $wfDeploymentService = $WorkflowServicesManager.GetWorkflowDeploymentService()

            # Load the Workflow XAML

            $xaml = $sourceXAML

            # Prepare the Workflow Definition object
            $wfDefinition = New-Object Microsoft.SharePoint.Client.WorkflowServices.WorkflowDefinition -ArgumentList $ClientContext
            $wfDefinition.DisplayName = $workflow
            $wfDefinition.Description = $sourceDefn.Description
            $wfDefinition.Xaml = $xaml.ToString()
            $wfDefinition.RestrictToType = $sourceDefn.RestrictToType
            # Define scope

            $scopeName = $SourceTable | Where-Object {$_.Id.Guid -eq $sourceDefn.RestrictToScope.Trim("{","}")}
            $destScope = $DestTable | Where-Object{$_.Title -eq $scopeName.Title}

            $wfDefinition.RestrictToScope = $destScope.id.Guid
            # Set SPD launch flags

            if($sourceDefn.Properties."SPDConfig.StartOnCreate" -eq $true){
                $wfDefinition.setProperty("SPDConfig.StartOnCreate", $true)
            if($sourceDefn.Properties."SPDConfig.StartOnChange" -eq $true){
                $wfDefinition.setProperty("SPDConfig.StartOnChange", $true)
            if($sourceDefn.Properties."SPDConfig.StartManually" -eq $true){
                $wfDefinition.setProperty("SPDConfig.StartManually", $true)

            # Save and publish the Workflow Definition object
            $definitionId = $wfDeploymentService.SaveDefinition($wfDefinition)

            # Publish the Workflow Definition

            # Retrieve IDs of targets (list/library, history, and tasks)
            $targetLibrary = $spWeb.Lists.GetByTitle($scopeName.Title)

            # Get History List Name
            $sourceHistoryListID = $sourcedefn.Properties.HistoryListId -Replace "[{}]",""
            $historyListName = $SourceTable | Where-Object {$_.Id.Guid -eq $sourceHistoryListID}

            $historyList = $spWeb.Lists.GetByTitle($historyListName.Title)

            # Get Task List Name
            $sourceTaskListID = $sourcedefn.Properties.TaskListId -Replace "[{}]",""
            $taskListName = $SourceTable | Where-Object {$_.Id.Guid -eq $sourceTaskListID}
            $tasksList = $spWeb.Lists.GetByTitle($taskListName.Title)


            # Associate the Workflow Definition to a target list/library
            $wfSubscriptionService = $WorkflowServicesManager.GetWorkflowSubscriptionService()
            $wfSubscription = New-Object Microsoft.SharePoint.Client.WorkflowServices.WorkflowSubscription -ArgumentList $ClientContext

            # Configure the Workflow Subscription
            $wfSubscription.DefinitionId = $definitionId.Value
            $wfSubscription.Name = $wfDefinition.DisplayName
            $wfSubscription.Enabled = $true

            $wfSubscription.EventTypes = $sourceSubs.EventTypes

            $wfSubscription.EventSourceId = $targetLibrary.Id.ToString()
            $wfSubscription.SetProperty(“TaskListId”, $tasksList.Id.ToString())
            $wfSubscription.SetProperty(“HistoryListId”, $historyList.Id.ToString())

            # Publish the Workflow Subscription
            $wfSubscriptionService.PublishSubscriptionForList($wfSubscription, $targetLibrary.Id.Guid)

    if($errors -ne $true){
        Write-Host "Updated $workflow on site $TargetAKPA" -ForegroundColor Cyan
    } else {
        Write-Host "Errors encountered" -ForegroundColor Red

Get this bounty!!!

#StackBounty: #linux #windows #powershell #visual-c++ #ssh Remote development of Visual C++ applications from Linux

Bounty: 50

Remote development on Linux from Windows is easily doable via SSH.

However, what about the other way? I need to build and debug my Visual C++ application on Windows, but I want to work on a Linux system.

  1. Cross-compiling via MinGW doesn’t work because of MSVC-specific libraries
  2. Ubuntu on Windows is a good start, but I’d like to work on a real Linux system
  3. RDP/VNC or something like that doesn’t help either, because than I’d work on Windows again
  4. So does a virtual machine

Maybe something like Powershell on Linux + SSH to the Windows Powershell?

Get this bounty!!!

#StackBounty: #powershell String in PowerShell ProgressBar not Displaying

Bounty: 50

I’m trying to use a PowerShell progress bar and the -status parameter isn’t working as advertised (or I’m reading the documentation incorrectly.

For simplicity sake, let’s say I have a collection:

@("red", "green", "blue")

… and I have another method which iterates through that collection. But when it iterates, the processing takes a long time. So I want to give status to the user by placing a call to progressBar($i, $s) in the loop.

There’s the code for progressBar:

function progressBar ($count, $color) {
  Write-Progress -Activity "My Progress Bar" -status "Doing stuff on $color" -percentComplete ($count / $totalItems * 100)

Which is corresponds with:


where the author uses this example:

-status "Found Service $i"

But when I run my script, nothing shows up after “Doing stuff on” — it’s blank!

I always thought + was concatenation in PS… but doing this -status "Doing stuff on " + $color fails too!

Before posting, I read this:

How do I concatenate strings and variables in PowerShell?

… and the suggestion to use $($color) makes the cmdlet fail all together.

So, how can I get my entire string to appear in -status rather than it dropping the $color part?



Hello again… I’m adding the full code per @BenH and @Persistent13’s comments below.

$a = @("red", "green", "blue")

$counter    = 1
$totalItems = $a.Count

foreach ($color in $a) {

Write-Host $color "`n"
Start-Sleep -s 3
$counter += 1

progressBar $counter, $color

function progressBar ($i, $s) {
  Write-Progress -Activity "My Progress Bar" -status "Doing stuff on $s" -percentComplete ($i / $totalItems * 100)

Get this bounty!!!