-PipelineVariable isnt working correctly

Welcome Forums General PowerShell Q&A -PipelineVariable isnt working correctly

This topic contains 25 replies, has 4 voices, and was last updated by

js
 
Participant
1 month ago.

  • Author
    Posts
  • #121299

    Participant
    Points: 90
    Rank: Member

    I have this script that changes services per a csv file input

    Import-CSV .\SSAS_services.csv |
    ForEach-Object{
    Get-Service $_.Service -ComputerName $_.Server -PipelineVariable svc|
    Set-Service -Status $_.Task -StartupType $_.'Startup Type' -PassThru
    } |
    Select-Object MachineName, Name, Status, StartType, @{n='OldStatus';e={$svc.Status}}, @{n='OldStartType';e={$svc.StartType}} | 
    tee-object -FilePath '.\ChangeServices_LOG.txt' #-Append

    csv file

    Server,Service,Startup Type,Task
    DCVPIM108,SQL Server Analysis Services (MSSQLSERVER),automatic,running
    server2,"SQL Server Analysis Services (MSSQLSERVER), SQL Server Analysis Services (MSSQLSERVER) CEIP",Manual,stopped

    my `-PipelineVariable svc`is not working as intended. if a service was "stopped" and "Manual" before being changed to "running" and "automatic", it doesnt get the old values "stopped" and "Manual" for `OldStatus` and `OldStartType`

    MachineName : DCVPIM108
    Name : MSSQLServerOLAPService
    Status : Running
    StartType : Automatic
    OldStatus : Running
    OldStartType : Automatic

  • #121320
    js

    Participant
    Points: 302
    Helping Hand
    Rank: Contributor

    I don't know what's in the csv file, but maybe you should put the select-object inside the foreach-object loop, which is probably running multiple times.

  • #121323

    Participant
    Points: 90
    Rank: Member

    I don't know what's in the csv file, but maybe you should put the select-object inside the foreach-object loop, which is probably running multiple times.

    i added the csv to my post, if i put select object inside then wouldnt it overwrite?

    • #121326
      js

      Participant
      Points: 302
      Helping Hand
      Rank: Contributor

      Can't you use "-append" like you have commented out?

  • #121327

    Participant
    Points: 90
    Rank: Member

    Can't you use "-append" like you have commented out?

    well append just appends to the file instead of overwriting it...

    anyways I did try putting the select inside the for loop for the suggestion, and it returned the same result as having it outside....

  • #121336
    js

    Participant
    Points: 302
    Helping Hand
    Rank: Contributor

    Looks like it dynamically updates those properties.

    PS C:\> get-service adobearmservice | gm | where name -match 'starttype|^status' 
    
    
       TypeName: System.ServiceProcess.ServiceController
    
    Name      MemberType Definition
    ----      ---------- ----------
    StartType Property   System.ServiceProcess.ServiceStartMode StartType {get;}
    Status    Property   System.ServiceProcess.ServiceControllerStatus Status {get;}
    
  • #121341

    Participant
    Points: 90
    Rank: Member

    Looks like it dynamically updates those properties.

    PowerShell
    10 lines

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    PS C:\> get-service adobearmservice | gm | where name -match 'starttype|^status'
    TypeName: System.ServiceProcess.ServiceController
    Name MemberType Definition
    —- ———- ———-
    StartType Property System.ServiceProcess.ServiceStartMode StartType {get;}
    Status Property System.ServiceProcess.ServiceControllerStatus Status {get;}
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    so in terms of my script, what should i do?

    • #121342
      js

      Participant
      Points: 302
      Helping Hand
      Rank: Contributor

      Maybe save things to a $oldstatus and a $oldstartype.

  • #121344

    Participant
    Points: 90
    Rank: Member

    but the whole point of e={$svc.Status} is it should be able to solve the expression from the -PipelineVariable....so then i would have to remove it from my script as its useless huh?

    • #121345
      js

      Participant
      Points: 302
      Helping Hand
      Rank: Contributor

      Yep.

  • #121348

    Participant
    Points: 90
    Rank: Member

    Yep.

    lol great. and the person who suggested this to me claimed he was an expert on microsoft support. i ended up wasting my time with this N and E expression...

    • #121362
      js

      Participant
      Points: 302
      Helping Hand
      Rank: Contributor

      It's a valid technique. This situation is unusual.

  • #121431

    Participant
    Points: 306
    Helping Hand
    Rank: Contributor

    Why do you have two service specified in your csv on the same line for server2?
    These should, IMHO, be separate line items relative to the types of getter / setter effort you are trying to do.
    The results are as shown below, and no issues observed even with the 'manual' or 'stopped' status.

    $SSAS_services = @"
    Server,Service,Startup Type,Task
    SQL01,Audiosrv,start
    SP01,Browser,Manual,stop
    SP01,BITS,Manual,stop
    "@  > 'C:\scripts\SSAS_services.csv'
    
    
    Clear-Host
    Import-CSV 'C:\Scripts\SSAS_services.csv' |
    ForEach-Object{Get-Service $_.Service -ComputerName $_.Server -PipelineVariable svc} | 
    Select-Object MachineName, Name, Status, StartType, 
    @{n='OldStatus';e={$svc.Status}}, 
    @{n='OldStartType';e={$svc.StartType}}
    
    # Results
    
    MachineName  : SQL01
    Name         : Audiosrv
    Status       : Running
    StartType    : Automatic
    OldStatus    : Running
    OldStartType : Automatic
    
    MachineName  : SP01
    Name         : Browser
    Status       : Stopped
    StartType    : Disabled
    OldStatus    : Stopped
    OldStartType : Disabled
    
    MachineName  : SP01
    Name         : BITS
    Status       : Stopped
    StartType    : Manual
    OldStatus    : Stopped
    OldStartType : Manual
    
  • #121435

    Participant
    Points: 90
    Rank: Member

    Why do you have two service specified in your csv on the same line for server2?

    These should, IMHO, be separate line items relative to the types of getter / setter effort you are trying to do.

    The results are as shown below, and no issues observed even with the 'manual' or 'stopped' status.

    PowerShell
    38 lines

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    $SSAS_services = @"
    Server,Service,Startup Type,Task
    SQL01,Audiosrv,start
    SP01,Browser,Manual,stop
    SP01,BITS,Manual,stop
    "@ > 'C:\scripts\SSAS_services.csv'
    Clear-Host
    Import-CSV 'C:\Scripts\SSAS_services.csv' |
    ForEach-Object{Get-Service $_.Service ComputerName $_.Server PipelineVariable svc} |
    Select-Object MachineName, Name, Status, StartType,
    @{n='OldStatus';e={$svc.Status}},
    @{n='OldStartType';e={$svc.StartType}}
    # Results
    MachineName : SQL01
    Name : Audiosrv
    Status : Running
    StartType : Automatic
    OldStatus : Running
    OldStartType : Automatic
    MachineName : SP01
    Name : Browser
    Status : Stopped
    StartType : Disabled
    OldStatus : Stopped
    OldStartType : Disabled
    MachineName : SP01
    Name : BITS
    Status : Stopped
    StartType : Manual
    OldStatus : Stopped
    OldStartType : Manual
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    Let's talk about SQL01 machine. Let's say the service was stopped, and set to manual start type.  Keep your csv file as is please and run the script. Paste results here (the old status should be different from new status, but that's not what I saw in those results, so pipelinevariable isnt working

  • #121489

    Participant
    Points: 90
    Rank: Member

    the output is not right.

    in my csv, if the service status is stopped, but it is running on the server, what SHOULD be outputted is:

    status: stopped

    oldStatus: running

    because the old status was running and because in csv file i defined it to stop running, the statuses would be different. that is my issue with -PipelineVariable svc. it should be getting the current status of the service BEFORE it gets set by the ensuing command.

    this applied to the startuptype btw.

     

    and sure, if i had the csv file say running and the service is already running, then cool, i would expect both to say the same thing. but the issue here is its NOT getting the current status before setting it.

  • #121500
    js

    Participant
    Points: 302
    Helping Hand
    Rank: Contributor

    By the way, 'start' isn't valid for the 'set-service -status' parameter in the csv. It should be 'running'.

  • #121515

    Participant
    Points: 90
    Rank: Member

    By the way, 'start' isn't valid for the 'set-service -status' parameter in the csv. It should be 'running'.

    Edited my post.

    As for your output,

    the output is not right.

    in my csv, if the service status is stopped, but it is running on the server, what SHOULD be outputted is:

    status: stopped

    oldStatus: running

    because the old status was running and because in csv file i defined it to stop running, the statuses would be different. that is my issue with -PipelineVariable svc. it should be getting the current status of the service BEFORE it gets set by the ensuing command.

    this applied to the startuptype btw.

     

    and sure, if i had the csv file say running and the service is already running, then cool, i would expect both to say the same thing. but the issue here is its NOT getting the current status before setting it.

     

  • #121525
    js

    Participant
    Points: 302
    Helping Hand
    Rank: Contributor

    Here's a way to do it. Note that tee saves as unicode like out-file.

    Import-CSV services.csv |
    ForEach {
      $a = Get-Service $_.service 
      $oldstatus = $a.status
      $oldstarttype = $a.starttype
      $a | Set-Service -Status $_.Task -StartupType $_.'Startup Type' -PassThru |
      Select Name, Status, StartType, @{n='OldStatus';e={$oldStatus}},
        @{n='OldStartType';e={$oldStartType}} 
    } |
    tee ChangeServices_LOG.txt
    
    
    Name         : AdobeARMservice
    Status       : Running
    StartType    : Automatic
    OldStatus    : Stopped
    OldStartType : Manual
    
    Name         : Apple Mobile Device Service
    Status       : Running
    StartType    : Automatic
    OldStatus    : Stopped
    OldStartType : Manual
    

    Csv:

    service,startup type,task
    AdobeARMservice,automatic,running
    Apple Mobile Device Service,automatic,running
    
  • #121531

    Participant
    Points: 90
    Rank: Member

    yessss finally! THAT is what i have been looking for! OMG that took so many days and so many resources to ask. not even stackoverflow folks knew how lol

    to summarize the problem for anyone in teh future having this issue:

    PipelineVariable is DYNAMIC. what this means is if the variable's properties is modified (i.e. set-service -status) then the status property will change and will ALSO change whatever the pipeline variable status was. this is unfortunate and it should not behave like this.

     

    THANK YOU JS! after 3 days this issue can finally be put to rest!

  • #121540
    js

    Participant
    Points: 302
    Helping Hand
    Rank: Contributor

    It's not that pipevariable is dynamic, but the StartType and Status properties in the ServiceController object are dynamic. I've never dealt with it before.

  • #121542

    Participant
    Points: 809
    Helping Hand
    Rank: Major Contributor

    Pipeline variable keeps the reference, The newly added member is also present in the pipeline variable which is represented in New column

    [PSCustomObject]@{Column1=1;Column2=2} | Select-Object -Property * -PipelineVariable rr | Foreach-Object -Process {$_.Column1=5;$_|Add-Member -MemberType NoteProperty -Name Column3 -Value 6;$_} | Select-Object -Property *,@{E={$rr};L='New'}
    
    Column1 Column2 Column3 New
    ------- ------- ------- ---
          5       2       6 @{Column1=5; Column2=2; Column3=6}
    
  • #121545

    Participant
    Points: 90
    Rank: Member

    Pipeline variable keeps the reference, The newly added member is present in the pipeline variable which is represented in New column

    1
    2
    [PSCustomObject]@{Column1=1;Column2=2} | Select-Object Property * PipelineVariable rr | Foreach-Object Process {$_.Column1=5;$_|Add-Member MemberType NoteProperty Name Column3 Value 6;$_} | Select-Object Property *,@{E={$rr};L='New'}
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    So in other words, its useless for my use case

  • #121563
    js

    Participant
    Points: 302
    Helping Hand
    Rank: Contributor

    Hmm, I guess that's true of all properties.

    $a = [pscustomobject]@{message='hi'}
    $b = $a
    $a.message = 'there'
    $b.message
    
    there
    
  • #121719

    Participant
    Points: 306
    Helping Hand
    Rank: Contributor

    Update from my last post back using your approach a bit differently. "correction pasted the wrong one"

    $SSAS_services = @"
    Server,Service,Startup Type,Task
    $env:COMPUTERNAME,AxInstSV,Manual,stopped
    "@  > 'D:\scripts\SSAS_services1.csv'
    
    Import-CSV 'D:\Scripts\SSAS_services1.csv' |
    ForEach-Object{
        $svc = Get-Service $_.Service -ComputerName $_.Server | Select MachineName, Name, StartType, Status
        Set-Service -ComputerName $_.Server -Service $_.Service -Status $_.Task -StartupType $_.'Startup Type' -PassThru | 
        Select MachineName, Name, StartType, Status,@{n='OldStartUp';e={$svc.StartType}},@{n='OldStatus';e={$svc.Status}}
    } 
    
    
    
    MachineName : LC01
    Name        : AxInstSV
    StartType   : Manual
    Status      : Stopped
    OldStartUp  : Manual
    OldStatus   : Stopped
    
    
    
    
    $SSAS_services = @"
    Server,Service,Startup Type,Task
    $env:COMPUTERNAME,AxInstSV,Disabled,stopped
    "@  > 'D:\scripts\SSAS_services1.csv'
    
    Import-CSV 'D:\Scripts\SSAS_services1.csv' |
    ForEach-Object{
        $svc = Get-Service $_.Service -ComputerName $_.Server | Select MachineName, Name, StartType, Status
        Set-Service -ComputerName $_.Server -Service $_.Service -Status $_.Task -StartupType $_.'Startup Type' -PassThru | 
        Select MachineName, Name, StartType, Status,@{n='OldStartUp';e={$svc.StartType}},@{n='OldStatus';e={$svc.Status}}
    } 
    
    
    
    
    MachineName : LC01
    Name        : AxInstSV
    StartType   : Disabled
    Status      : Stopped
    OldStartUp  : Manual
    OldStatus   : Stopped
    
    
    
    
    $SSAS_services = @"
    Server,Service,Startup Type,Task
    $env:COMPUTERNAME,AxInstSV,Manual,stopped
    "@  > 'D:\scripts\SSAS_services1.csv'
    
    Import-CSV 'D:\Scripts\SSAS_services1.csv' |
    ForEach-Object{
        $svc = Get-Service $_.Service -ComputerName $_.Server | Select MachineName, Name, StartType, Status
        Set-Service -ComputerName $_.Server -Service $_.Service -Status $_.Task -StartupType $_.'Startup Type' -PassThru | 
        Select MachineName, Name, StartType, Status,@{n='OldStartUp';e={$svc.StartType}},@{n='OldStatus';e={$svc.Status}}
    } 
    
    
    
    MachineName : LC01
    Name        : AxInstSV
    StartType   : Manual
    Status      : Stopped
    OldStartUp  : Disabled
    OldStatus   : Stopped
  • #121729

    Participant
    Points: 90
    Rank: Member

    Update from my last post back using your approach a bit differently.

    PowerShell
    57 lines

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    $SSAS_services = @"
    Server,Service,Startup Type,Task
    $env:COMPUTERNAME,AxInstSV,Manual,stopped
    "@ > 'D:\scripts\SSAS_services1.csv'
    Import-CSV 'D:\Scripts\SSAS_services1.csv' |
    ForEach-Object{
    Get-Service $_.Service ComputerName $_.Server PipelineVariable svc
    Set-Service ComputerName $_.Server Service $_.Service Status $_.Task StartupType $_.'Startup Type' PassThru
    } | Select-Object Property MachineName, Name, StartType, Status,
    @{n='OldStartType';e={$_.StartType}}, @{n='OldStatus';e={$_.Status}}
    MachineName : LP70
    Name : AxInstSV
    StartType : Manual
    Status : Stopped
    OldStartType : Manual
    OldStatus : Stopped
    MachineName : LP70
    Name : AxInstSV
    StartType : Manual
    Status : Stopped
    OldStartType : Manual
    OldStatus : Stopped
    $SSAS_services = @"
    Server,Service,Startup Type,Task
    $env:COMPUTERNAME,AxInstSV,Disable,stopped
    "@ > 'D:\scripts\SSAS_services1.csv'
    Import-CSV 'D:\Scripts\SSAS_services1.csv' |
    ForEach-Object{
    Get-Service $_.Service ComputerName $_.Server PipelineVariable svc
    Set-Service ComputerName $_.Server Service $_.Service Status $_.Task StartupType $_.'Startup Type' PassThru
    } | Select-Object Property MachineName, Name, StartType, Status,
    @{n='OldStartType';e={$_.StartType}}, @{n='OldStatus';e={$_.Status}}
    MachineName : LabPC01
    Name : AxInstSV
    StartType : Manual
    Status : Stopped
    OldStartType : Manual
    OldStatus : Stopped
    MachineName : LabPC01
    Name : AxInstSV
    StartType : Disabled
    Status : Stopped
    OldStartType : Disabled
    OldStatus : Stopped
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    Not sure if it's a response to JS, but if for me, the results are wrong here, unless the system was already the same states as in the csv file.

  • #121906
    js

    Participant
    Points: 302
    Helping Hand
    Rank: Contributor

    A way to copy the values of an object (clone) (https://kevinmarquette.github.io/2016-10-28-powershell-everything-you-wanted-to-know-about-pscustomobject/#psobjectcopy). Why does psobject have to be hidden?

    $a = [pscustomobject]@{message='hi'}
    $a.message
    hi
    
    $b = $a.psobject.copy()
    $b.message
    hi
    
    $a.message = 'there'
    $a.message
    there
    
    $b.message
    hi
    

You must be logged in to reply to this topic.