PowerShell से .ps1 स्क्रिप्ट को पैरामीटर्स और क्रेडेंशियल्स के साथ शुरू करना और वेरिएबल का उपयोग करके आउटपुट प्राप्त करना


10

हैलो स्टैक कम्युनिटी :)

मेरा एक आसान लक्ष्य है। मैं एक और पॉवर्सशेल स्क्रिप्ट से कुछ PowerShell स्क्रिप्ट शुरू करना चाहता हूं, लेकिन 3 शर्तें हैं:

  1. मुझे क्रेडेंशियल पास करना होगा (निष्पादन एक डेटाबेस से जुड़ता है जिसमें विशिष्ट उपयोगकर्ता होता है)
  2. इसमें कुछ Parameters लेने पड़ते हैं
  3. मैं एक चर में उत्पादन पारित करना चाहते हैं

इसी तरह का प्रश्न लिंक है । लेकिन इसका जवाब 2 पीएस लिपियों के बीच संवाद करने के तरीके के रूप में फ़ाइलों का उपयोग करना है। मैं सिर्फ पहुंच संघर्ष से बचना चाहूंगा। @ यूपीडेट: मुख्य स्क्रिप्ट कुछ अन्य स्क्रिप्ट शुरू करने जा रही है। इसलिए फाइलों के साथ समाधान मुश्किल हो सकता है, अगर निष्पादन एक ही समय में कई उपयोगकर्ता से किया जाएगा।

Script1.ps1 वह स्क्रिप्ट है जिसमें एक आउटपुट के रूप में स्ट्रिंग होनी चाहिए। (बस स्पष्ट होने के लिए, यह एक काल्पनिक स्क्रिप्ट है, असली में 150 पंक्तियां हैं, इसलिए मैं सिर्फ एक उदाहरण बनाना चाहता था)

param(  
[String]$DeviceName
)
#Some code that needs special credentials
$a = "Device is: " + $DeviceName
$a

ExecuteScripts.ps1 को उपरोक्त वर्णित 3 शर्तों के साथ एक को आमंत्रित करना चाहिए

मैंने कई उपाय आजमाए। परीक्षा के लिए यह एक:

$arguments = "C:\..\script1.ps1" + " -ClientName" + $DeviceName
$output = Start-Process powershell -ArgumentList $arguments -Credential $credentials
$output 

मुझे उससे कोई आउटपुट नहीं मिलता है और मैं सिर्फ स्क्रिप्ट को कॉल नहीं कर सकता

&C:\..\script1.ps1 -ClientName PCPC

क्योंकि मैं -Credentialइसे करने के लिए पैरामीटर पारित नहीं कर सकते ..

आपका अग्रिम में ही बहुत धन्यवाद!


यदि यह सिर्फ संघर्षों के बारे में है: हर आह्वान के लिए अद्वितीय फ़ाइलनाम बनाने से आपकी समस्या का समाधान होगा, है ना?
mklement0

1
@ mklement0 यदि यह एकमात्र तरीका है, तो मैं उस समाधान के साथ ढेर हो जाऊंगा। बस यादृच्छिक फ़ाइल नाम उत्पन्न करना, जाँच करना कि क्या ऐसी फ़ाइल मौजूद है ... मैं अपने जावा कोड से 6 से 10 स्क्रिप्ट निष्पादित कर रहा हूं और इसे हर बार 6 से 10 फ़ाइलों की आवश्यकता होगी, जिसका मैं उपयोग कर रहा हूं या कोई अन्य मेरे एप्लिकेशन का उपयोग करता है। तो इसके प्रदर्शन के बारे में भी
Dmytro

जवाबों:


2

ध्यान दें:

  • निम्न समाधान किसी भी बाहरी प्रोग्राम के साथ काम करता है , और आउटपुट को टेक्स्ट के रूप में हमेशा कैप्चर करता है

  • किसी अन्य PowerShell उदाहरण को आमंत्रित करने के लिए और इसके आउटपुट को रिच ऑब्जेक्ट्स (सीमाओं के साथ) के रूप में कैप्चर करने के लिए , नीचे अनुभाग में वेरिएंट समाधान देखें या Mathias R. Jessen के सहायक उत्तर पर विचार करें , जो PowerShell SDK का उपयोग करता है ।

स्मृति में प्रक्रिया आउटपुट को कैप्चर करने के लिए .NET और .NET प्रकार के प्रत्यक्ष उपयोग केSystem.Diagnostics.ProcessSystem.Diagnostics.ProcessStartInfo आधार पर यहां एक अवधारणा है (जैसा कि आपके प्रश्न में कहा गया है, Start-Processविकल्प नहीं है, क्योंकि यह केवल फाइलों में आउटपुट कैप्चर करने का समर्थन करता है , जैसा कि इस उत्तर में दिखाया गया है ) :

ध्यान दें:

  • एक अलग उपयोगकर्ता के रूप में चलने के कारण, यह केवल विंडोज़ पर समर्थित है (.NET कोर 3.1 के रूप में), लेकिन पावरशेल संस्करणों में दोनों।

  • एक अलग उपयोगकर्ता के रूप में चलाने के लिए और आउटपुट पर कब्जा करने की आवश्यकता के कारण, छिपी हुई.WindowStyle कमांड को चलाने के लिए उपयोग नहीं किया जा सकता है (क्योंकि उपयोग करने के लिए इन आवश्यकताओं के साथ असंगत होना चाहिए ); हालांकि, के बाद से सभी उत्पादन किया जा रहा है पर कब्जा कर लिया , स्थापित करने के लिए प्रभावी ढंग से छुपा निष्पादन का परिणाम है।.WindowStyle.UseShellExecute$true.CreateNoNewWindow$true

# Get the target user's name and password.
$cred = Get-Credential

# Create a ProcessStartInfo instance
# with the relevant properties.
$psi = [System.Diagnostics.ProcessStartInfo] @{
  # For demo purposes, use a simple `cmd.exe` command that echoes the username. 
  # See the bottom section for a call to `powershell.exe`.
  FileName = 'cmd.exe'
  Arguments = '/c echo %USERNAME%'
  # Set this to a directory that the target user
  # is permitted to access.
  WorkingDirectory = 'C:\'                                                                   #'
  # Ask that output be captured in the
  # .StandardOutput / .StandardError properties of
  # the Process object created later.
  UseShellExecute = $false # must be $false
  RedirectStandardOutput = $true
  RedirectStandardError = $true
  # Uncomment this line if you want the process to run effectively hidden.
  #   CreateNoNewWindow = $true
  # Specify the user identity.
  # Note: If you specify a UPN in .UserName
  # (user@doamin.com), set .Domain to $null
  Domain = $env:USERDOMAIN
  UserName = $cred.UserName
  Password = $cred.Password
}

# Create (launch) the process...
$ps = [System.Diagnostics.Process]::Start($psi)

# Read the captured standard output.
# By reading to the *end*, this implicitly waits for (near) termination
# of the process.
# Do NOT use $ps.WaitForExit() first, as that can result in a deadlock.
$stdout = $ps.StandardOutput.ReadToEnd()

# Uncomment the following lines to report the process' exit code.
#   $ps.WaitForExit()
#   "Process exit code: $($ps.ExitCode)"

"Running ``cmd /c echo %USERNAME%`` as user $($cred.UserName) yielded:"
$stdout

उपरोक्त कुछ निम्न की तरह देता है, जिसमें दिखाया गया है कि यह प्रक्रिया दी गई उपयोगकर्ता पहचान के साथ सफलतापूर्वक चलती है:

Running `cmd /c echo %USERNAME%` as user jdoe yielded:
jdoe

जब से आप एक और PowerShell उदाहरण को कॉल कर रहे हैं , आप CLIXML प्रारूप में आउटपुट का प्रतिनिधित्व करने के लिए PowerShell CLI की क्षमता का लाभ उठाना चाह सकते हैं , जो आउटपुट को समृद्ध वस्तुओं में निष्क्रिय करने की अनुमति देता है , सीमित प्रकार की निष्ठा के साथ , जैसा कि इस संबंधित उत्तर में बताया गया है। ।

# Get the target user's name and password.
$cred = Get-Credential

# Create a ProcessStartInfo instance
# with the relevant properties.
$psi = [System.Diagnostics.ProcessStartInfo] @{
  # Invoke the PowerShell CLI with a simple sample command
  # that calls `Get-Date` to output the current date as a [datetime] instance.
  FileName = 'powershell.exe'
  # `-of xml` asks that the output be returned as CLIXML,
  # a serialization format that allows deserialization into
  # rich objects.
  Arguments = '-of xml -noprofile -c Get-Date'
  # Set this to a directory that the target user
  # is permitted to access.
  WorkingDirectory = 'C:\'                                                                   #'
  # Ask that output be captured in the
  # .StandardOutput / .StandardError properties of
  # the Process object created later.
  UseShellExecute = $false # must be $false
  RedirectStandardOutput = $true
  RedirectStandardError = $true
  # Uncomment this line if you want the process to run effectively hidden.
  #   CreateNoNewWindow = $true
  # Specify the user identity.
  # Note: If you specify a UPN in .UserName
  # (user@doamin.com), set .Domain to $null
  Domain = $env:USERDOMAIN
  UserName = $cred.UserName
  Password = $cred.Password
}

# Create (launch) the process...
$ps = [System.Diagnostics.Process]::Start($psi)

# Read the captured standard output, in CLIXML format,
# stripping the `#` comment line at the top (`#< CLIXML`)
# which the deserializer doesn't know how to handle.
$stdoutCliXml = $ps.StandardOutput.ReadToEnd() -replace '^#.*\r?\n'

# Uncomment the following lines to report the process' exit code.
#   $ps.WaitForExit()
#   "Process exit code: $($ps.ExitCode)"

# Use PowerShell's deserialization API to 
# "rehydrate" the objects.
$stdoutObjects = [Management.Automation.PSSerializer]::Deserialize($stdoutCliXml)

"Running ``Get-Date`` as user $($cred.UserName) yielded:"
$stdoutObjects
"`nas data type:"
$stdoutObjects.GetType().FullName

उपरोक्त कुछ निम्न जैसा आउटपुट देता है, यह दर्शाता है कि [datetime]उदाहरण ( System.DateTime) द्वारा आउटपुट Get-Dateको इस तरह से deserialized किया गया था:

Running `Get-Date` as user jdoe yielded:

Friday, March 27, 2020 6:26:49 PM

as data type:
System.DateTime

5

Start-ProcessPowerShell से PowerShell को लागू करने के लिए मेरा अंतिम विकल्प होगा - विशेषकर क्योंकि सभी I / O स्ट्रिंग्स बन जाते हैं और न ही (डिसेरिएलाइज्ड) ऑब्जेक्ट।

दो विकल्प:

1. यदि उपयोगकर्ता एक स्थानीय व्यवस्थापक है और PSRemoting कॉन्फ़िगर किया गया है

अगर स्थानीय मशीन के खिलाफ एक दूरस्थ सत्र (दुर्भाग्य से स्थानीय व्यवस्थापक तक सीमित है) एक विकल्प है, तो मैं निश्चित रूप से साथ जाऊंगा Invoke-Command:

$strings = Invoke-Command -FilePath C:\...\script1.ps1 -ComputerName localhost -Credential $credential

$strings परिणाम शामिल होंगे।


2. यदि उपयोगकर्ता लक्ष्य प्रणाली पर एक व्यवस्थापक नहीं है

आप अपने स्वयं के "स्थानीय-केवल Invoke-Command" लिख सकते हैं :

  1. एक PowerShellProcessInstance, एक अलग लॉगिन के तहत बनाना
  2. उक्त प्रक्रिया में एक रनस्पेस बनाना
  3. कहा आउट-ऑफ-प्रोसेस रनस्पेस में अपना कोड निष्पादित करें

मैं एक साथ इस तरह के एक समारोह के नीचे रख दिया, टहलने के लिए इनलाइन टिप्पणी देखें:

function Invoke-RunAs
{
    [CmdletBinding()]
    param(
        [Alias('PSPath')]
        [ValidateScript({Test-Path $_ -PathType Leaf})]
        [Parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
        [string]
        ${FilePath},

        [Parameter(Mandatory = $true)]
        [pscredential]
        [System.Management.Automation.CredentialAttribute()]
        ${Credential},

        [Alias('Args')]
        [Parameter(ValueFromRemainingArguments = $true)]
        [System.Object[]]
        ${ArgumentList},

        [Parameter(Position = 1)]
        [System.Collections.IDictionary]
        $NamedArguments
    )

    begin
    {
        # First we set up a separate managed powershell process
        Write-Verbose "Creating PowerShellProcessInstance and runspace"
        $ProcessInstance = [System.Management.Automation.Runspaces.PowerShellProcessInstance]::new($PSVersionTable.PSVersion, $Credential, $null, $false)

        # And then we create a new runspace in said process
        $Runspace = [runspacefactory]::CreateOutOfProcessRunspace($null, $ProcessInstance)
        $Runspace.Open()
        Write-Verbose "Runspace state is $($Runspace.RunspaceStateInfo)"
    }

    process
    {
        foreach($path in $FilePath){
            Write-Verbose "In process block, Path:'$path'"
            try{
                # Add script file to the code we'll be running
                $powershell = [powershell]::Create([initialsessionstate]::CreateDefault2()).AddCommand((Resolve-Path $path).ProviderPath, $true)

                # Add named param args, if any
                if($PSBoundParameters.ContainsKey('NamedArguments')){
                    Write-Verbose "Adding named arguments to script"
                    $powershell = $powershell.AddParameters($NamedArguments)
                }

                # Add argument list values if present
                if($PSBoundParameters.ContainsKey('ArgumentList')){
                    Write-Verbose "Adding unnamed arguments to script"
                    foreach($arg in $ArgumentList){
                        $powershell = $powershell.AddArgument($arg)
                    }
                }

                # Attach to out-of-process runspace
                $powershell.Runspace = $Runspace

                # Invoke, let output bubble up to caller
                $powershell.Invoke()

                if($powershell.HadErrors){
                    foreach($e in $powershell.Streams.Error){
                        Write-Error $e
                    }
                }
            }
            finally{
                # clean up
                if($powershell -is [IDisposable]){
                    $powershell.Dispose()
                }
            }
        }
    }

    end
    {
        foreach($target in $ProcessInstance,$Runspace){
            # clean up
            if($target -is [IDisposable]){
                $target.Dispose()
            }
        }
    }
}

तो इस तरह का उपयोग करें:

$output = Invoke-RunAs -FilePath C:\path\to\script1.ps1 -Credential $targetUser -NamedArguments @{ClientDevice = "ClientName"}

0

rcv.ps1

param(
    $username,
    $password
)

"The user is:  $username"
"My super secret password is:  $password"

किसी अन्य स्क्रिप्ट से निष्पादन:

.\rcv.ps1 'user' 'supersecretpassword'

उत्पादन:

The user is:  user
My super secret password is:  supersecretpassword

1
मैं इस exectuion को credentails पारित करने के लिए है ...
दमयेत्रो

प्रासंगिक भागों को अद्यतन किया।
thepip3r

स्पष्ट करने के लिए: अभिप्राय केवल क्रेडेंशियल पास करना नहीं है, बल्कि क्रेडेंशियल्स द्वारा पहचाने गए उपयोगकर्ता के रूप में चलना है
mklement0

1
@ mklement0, स्पष्टीकरण के लिए धन्यवाद क्योंकि यह सवाल के विभिन्न पुनरावृत्तियों द्वारा मेरे लिए बिल्कुल स्पष्ट नहीं था।
thepip3r

0

क्या आप इसे एक ps1 स्क्रिप्ट के लिए एक पैरामीटर पारित करने के लिए निम्नलिखित कर सकते हैं।

पहली स्क्रिप्ट एक मूल.प्स 1 हो सकती है जहाँ हम लिखते हैं:

& C:\scripts\dest.ps1 Pa$$w0rd parameter_a parameter_n

Th गंतव्य स्क्रिप्ट dest.ps1 चर को पकड़ने के लिए निम्न कोड हो सकता है

$var0 = $args[0]
$var1 = $args[1]
$var2 = $args[2]
Write-Host "my args",$var0,",",$var1,",",$var2

और परिणाम होगा

my args Pa$$w0rd, parameter_a, parameter_n

1
मुख्य लक्ष्य सभी स्थितियों को 1 निष्पादन में संयोजित करना है। मुझे मापदंडों को पारित करना होगा और क्रेडेंशियल पास करना होगा!
दिमित्रो

"1 निष्पादन में सभी स्थितियों को संयोजित करें" से आपका क्या अभिप्राय है। मुझे नहीं लगता कि आप जैसे "-" प्रतीक के साथ एक पैरामीटर जोड़ सकते हैं .. मुझे लगता है कि आपको गंतव्य स्क्रिप्ट पर स्ट्रिंग्स को पुन: स्वरूपित करना होगा
एंडी मैकरै

मुझे मापदंडों के साथ कुछ PS1 फ़ाइल निष्पादित करनी चाहिए और -Credential $credentialsइस निष्पादन के लिए पैरामीटर पास करना चाहिए और इसे एक चर में आउटपुट प्राप्त करना चाहिए। Ps1। स्क्रिप्ट इम एग्जिक्यूटिंग अंत में एक सिंग शब्द स्ट्रिंग फेंक रहा है। बस जिस तरह से मैंने इसे किया था पर देखो, Start-processलेकिन यह फ़ंक्शन आउटपुट उत्पन्न नहीं करता है
Dmytro

मुझे लगता है कि Powerhell आपको इस $ तर्क = "C: \ .. \ script1.ps1" + "-ClientName" + $ DeviceName जैसे पैरामीटर को पारित करने की अनुमति नहीं देता है। आपको शायद "-" को हटाने के बारे में सोचना चाहिए
एंडी मैकरै

1
उस मधुमक्खी ने कहा। स्टार्ट-प्रोसेस पैरामीटर और क्रेडेंशियल के साथ स्क्रिप्ट को निष्पादित करता है, बिट यह आउटपुट को एक चर में नहीं बचाता है। यदि $outputवेरिएबल एक्सेस करने की कोशिश कर रहा है , तो यह NULL है। अन्य आइडिया जो @ mklement0 से आया है, आउटपुट को एक फाइल में सेव करना है। लेकिन मेरे मामले में यह एक ही स्थान पर बड़ी मात्रा में फ़ाइलों का कारण होगा। सभी को अलग-अलग स्क्रिप्ट के साथ अलग-अलग उपयोगकर्ताओं से बनाया गया है
Dmytro
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.